C语言基础:指针相关概念(指针的算术运算 指针数组指向指针的指针 传递指针给函数 从函数返回指针 )为啥C 语言不支持在调用函数时返回局部变量的地址?

Posted CodeJiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言基础:指针相关概念(指针的算术运算 指针数组指向指针的指针 传递指针给函数 从函数返回指针 )为啥C 语言不支持在调用函数时返回局部变量的地址?相关的知识,希望对你有一定的参考价值。

01:C语言基础:指针基础(概念,如何使用,NULL指针(空指针))
02:C语言基础:指针相关概念(指针的算术运算 、指针数组、指向指针的指针 、传递指针给函数 、从函数返回指针 )、为啥C 语言不支持在调用函数时返回局部变量的地址?

1. 指针相关概念

在 C 中,有很多指针相关的概念,这些概念都很简单,但是都很重要。下面列出了 C 程序员必须清楚的一些与指针相关的重要概念:

概念描述
指针的算术运算可以对指针进行四种算术运算:++、--、+、-
指针数组可以定义用来存储指针的数组。
指向指针的指针C 允许指向指针的指针。
传递指针给函数通过引用或地址传递参数,使传递的参数在调用函数中被改变。
从函数返回指针C 允许函数返回指针到局部变量、静态变量和动态内存分配。

1.1 指针的算术运算

C 指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-

假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:

ptr++;

在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。

小结:

  • 指针的每一次递增,它其实会指向下一个元素的存储单元。
  • 指针的每一次递减,它都会指向前一个元素的存储单元。
  • 指针在递增和递减时跳跃的字节数取决于指针所指向变量数据类型长度,比如 int 就是 4 个字节。

1.1.1 递增一个指针

我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,数组可以看成一个指针常量。下面的程序递增变量指针,以便顺序访问数组中的每一个元素:

#include <stdio.h>

const int MAX = 3;

int main () 
	int  var[] = 10, 100, 200;
	int  i, *ptr;

	/* 指针中的数组地址 */
	ptr = var;// ptr = &var[0]
	for ( i = 0; i < MAX; i++) 

		printf("存储地址:var[%d] = %p\\n", i, ptr );
		printf("存储值:var[%d] = %d\\n", i, *ptr );

		/* 指向下一个位置 */
		ptr++;
	
	return 0;

运行结果:


1.1.2 递减一个指针

同样地,对指针进行递减运算,即把值减去其数据类型的字节


1.1.3 指针的比较

指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。

下面的程序修改了上面的实例,只要变量指针所指向的地址小于或等于数组的最后一个元素的地址 &var[MAX - 1],则把变量指针进行递增:

#include <stdio.h>

const int MAX = 3;

int main () 
	int  var[] = 10, 100, 200;
	int  i, *ptr;

	/* 指针中第一个元素的地址 */
	ptr = var;
	i = 0;
	while ( ptr <= &var[MAX - 1] ) 

		printf("存储地址:var[%d] = %p\\n", i, ptr );
		printf("存储值:var[%d] = %d\\n", i, *ptr );

		/* 指向上一个位置 */
		ptr++;
		i++;
	
	return 0;

运行结果:


1.2 指针数组

让数组存储指向 int 或 char 或其他数据类型的指针。下面是一个指向整数的指针数组的声明:

int *ptr[MAX];

在这里,把 ptr 声明为一个数组,由 MAX 个整数指针组成。因此,ptr 中的每个元素,都是一个指向 int 值的指针。下面的实例用到了三个整数,它们将存储在一个指针数组中,如下所示:

#include <stdio.h>

const int MAX = 3;

int main () 
	int  var[] = 10, 100, 200;
	int i, *ptr[MAX];

	for ( i = 0; i < MAX; i++) 
		ptr[i] = &var[i]; /* 赋值为整数的地址 */
	
	for ( i = 0; i < MAX; i++) 
		printf("Value of var[%d] = %d\\n", i, *ptr[i] );
	
	return 0;

运行结果:

您也可以用一个指向字符的指针数组来存储一个字符串列表,如下:

#include <stdio.h>

const int MAX = 4;

int main () 
	const char *names[] = 
		"余宝贝",
		"磊宝贝",
		"旭宝贝",
		"曦宝贝",
	;
	int i = 0;

	for ( i = 0; i < MAX; i++) 
		printf("Value of names[%d] = %s\\n", i, names[i] );
	
	return 0;

运行结果:


1.3 指向指针的指针

指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。

一个指向指针的指针变量必须如下声明,即在变量名前放置两个星号。例如,下面声明了一个指向 int 类型指针的指针:

int **var; // 或者 int** var;

当一个目标值被一个指针间接指向到另一个指针时,访问这个值需要使用两个星号运算符,如下面实例所示:

运行结果:


1.4 传递指针给函数

C 语言允许您传递指针给函数,只需要简单地声明函数参数为指针类型即可。

下面的实例中,我们传递一个无符号的 long 型指针给函数,并在函数内改变这个值:

#include <stdio.h>
#include <time.h>

void getSeconds(unsigned long *par);

int main () 
	unsigned long sec;


	getSeconds( &sec );

	/* 输出实际值 */
	printf("Number of seconds: %ld\\n", sec );

	return 0;


void getSeconds(unsigned long* par) 
	/* 获取当前的秒数 */
	*par = time( NULL );
	return;

运行结果:

能接受指针作为参数的函数,也能接受数组作为参数,如下所示:

#include <stdio.h>

/* 函数声明 */
double getAverage(int *arr, int size);

int main () 
	/* 带有 5 个元素的整型数组  */
	int balance[5] = 1000, 2, 3, 17, 50;
	double avg;

	/* 传递一个指向数组的指针作为参数 */
	avg = getAverage( balance, 5 ) ;

	/* 输出返回值  */
	printf("Average value is: %f\\n", avg );

	return 0;


double getAverage(int *arr, int size) 
	int    i, sum = 0;
	double avg;

	for (i = 0; i < size; ++i) 
		sum += arr[i];
	

	avg = (double)sum / size;

	return avg;

运行结果:


1.5 从函数返回指针

C 允许您从函数返回指针。为了做到这点,您必须声明一个返回指针的函数,如下所示:

int * myFunction()...

C 语言不支持在调用函数时返回局部变量的地址,除非定义局部变量为 static 变量。

现在,让我们来看下面的函数,它会生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

/* 要生成和返回随机数的函数 */
int * getRandom( ) 
	static int  r[10];
	int i;

	/* 设置种子 */
	srand( (unsigned)time( NULL ) );
	for ( i = 0; i < 10; ++i) 
		r[i] = rand();
		printf("%d\\n", r[i] );
	

	return r;


/* 要调用上面定义函数的主函数 */
int main () 
	/* 一个指向整数的指针 */
	int* p;
	int i;

	p = getRandom();
	for ( i = 0; i < 10; i++ ) 
		printf("*(p + [%d]) : %d\\n", i, *(p + i) );
	

	return 0;

运行结果:


1.6 补充说明:为啥C 语言不支持在调用函数时返回局部变量的地址?

C 不支持在调用函数时返回局部变量的地址,除非定义局部变量为 static 变量。

因为局部变量是存储在内存的栈区内,当函数调用结束后,局部变量所占的内存地址便被释放了,因此当其函数执行完毕后,函数内的变量便不再拥有那个内存地址,所以不能返回其指针。

除非将其变量定义为 static 变量,static 变量的值存放在内存中的静态数据区,不会随着函数执行的结束而被清除,故能返回其地址。



以上是关于C语言基础:指针相关概念(指针的算术运算 指针数组指向指针的指针 传递指针给函数 从函数返回指针 )为啥C 语言不支持在调用函数时返回局部变量的地址?的主要内容,如果未能解决你的问题,请参考以下文章

C语言基础:指针基础(概念,如何使用,NULL指针(空指针))

40篇学完C语言——(第七篇)地址算术运算

C语言指针用法详解 指针的算术运算

C++ Primer Plus基础知识部分快速通关

C 语言结构体 ( 指针运算与指针内存操作 | 结构体成员偏移量计算 )

C语言中地址与指针相关概念