C语言之深入指针(二)(详细教程)

C语言之深入指针

文章目录

  • C语言之深入指针
    • 1. 传值调用和传址调用
    • 2. 数组名的理解
    • 3. 使用指针访问数组
    • 3. ⼀维数组传参的本质

1. 传值调用和传址调用

写一个函数用来交换a b的值

传值调用:

#include 
void Swap1(int x, int y)
{
	int tmp = 0;
	tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:%d %d\n", a, b);
	Swap1(a, b);
	printf("交换后:%d %d\n", a, b);
	return 0;
}

代码运行结果如下:
在这里插入图片描述
从运行结果可以看到,a和b的值并没有进行交换,因为传给Swap1函数的只是a和b的值,在Swap1函数内部创建了a和b的临时备份,也就是将实参传给了形参,形参有自己的内存空间,对形参的修改并不会影响实参
这种函数调用方式是:传值调用

结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实

传址调用:

#include 
void Swap2(int* x, int* y)
{
	int tmp = 0;
	tmp = *x;
	*x = *y;
	*y = tmp;
}

int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:%d %d\n", a, b);
	Swap2(&a, &b);
	printf("交换后:%d %d\n", a, b);
	return 0;
}

在这里插入图片描述
从运行结果可以看出,a和b的值有进行交换,这是因为传给Swap2函数的是a和b的地址,然后Swap2函数用两个指针变量来储存a和b的地址,所以在函数中改变x和y的值,由于是相同地址,所以a和b的值也会改变,着这种函数调用方式是:传址调用

2. 数组名的理解

先来看段代码:

#include 
int main()
{
	int arr[10] = { 0 };
	printf(" arr    = %p\n", arr);
	printf("&arr[0] = %p\n", &arr[0]);
	return 0;
}

代码运行结果:
在这里插入图片描述

从运行结果来看,arr和&arr[0]的打印出来的地址都是相同的,可以得知道,数组名就是数组⾸元素(第⼀个元素)的地址

但是有两个情况是例外

  1. • sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,
    单位是字节
  2. • &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素
    的地址是有区别的)
//情况1
#include 
int main()
{
	int arr[10] = { 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d", sz);
	return 0;
}

在以上情况下,sizeof中的数组名是表示整个数组,计算的是整个数组的大小

#include 
int main()
{
	int arr[10] = { 0 };
	/*int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d", sz);*/
	printf(" arr    = %p\n", arr);
	printf("&arr    = %p\n", &arr);
	printf("&arr[0] = %p\n", &arr[0]);
	return 0;
}

在这里插入图片描述

从运行结果看出,arr,&arr和&arr[0]打印的地址是一样的,都是首元素地址,arr和&arr[0]都是表示首元素的地址,那么arr和&arr有什么区别嘛
再来看一段代码:

#include 
int main()
{
	int arr[10] = { 0 };
	/*int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d", sz);*/
	printf(" arr      = %p\n", arr);
	printf(" arr + 1  = %p\n", arr+1);
	printf("&arr      = %p\n", &arr);
	printf("&arr + 1  = %p\n", &arr+1);
	printf("&arr[0]   = %p\n", &arr[0]);
	printf("&arr[0]+1 = %p\n", &arr[0]+1);
	return 0;
}

运行结果如下:
C语言之深入指针(二)(详细教程)_第1张图片
从结果可以看出
arr + 1 从~B78 变成了 ~B7C 加上了4个字节的空间
&arr + 1从~B78 变成了 ~BA0 由于是16进制,转换为二进制就是从120变成了160 加上了40个字节的空间
&arr[0] + 1和arr + 1的结果一样,都是加上了4个字节

• 结论 arr + 1 表示跳过4个字节也就是一个元素,而&arr + 1 表示跳过40个字节,也就是一整个数组

3. 使用指针访问数组

#include 
int main()
{
	int arr[10] = { 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);  //求数组中元素的个数
	int* p = arr;
	int i = 0;
	for(i=0;i<sz;i++)
	{
		//输入10个数 以下方法都可以
		scanf("%d", p + i);
	    /*scanf("%d", arr+i);*/
	}
	for (i = 0; i < sz; i++)
	{
		//输出10个数 以下方法都可以
		printf("%d ", *(p + i)); 
		/*printf("%d ", p[i]);*/
		/*printf("%d ", *(arr + i));*/
		/*printf("%d ", arr[i]); */
		/*printf("%d ", i[arr]);*/
	}
	return 0;
}

p + i 等价于 arr + i
p [ i ] 等价于 *( p + i )
arr[ i ] 等价于 *( arr + i )
都是通过首元素的地址 + 偏移量,然后解引用来访问数组的元素
arr[ i ] 编译器会转换成 *( arr + i )来处理的,例如加法的交换律a+b可以写成b+a,那么也可以写成 *(i + arr),所以也就可以写成 i [arr],但是不建议这样写,代码的可读性极低,只是做个了解

3. ⼀维数组传参的本质

给定一共整形数组,求数组的的元素个数

#include 
void test1(int arr[])//参数写成数组形式,本质上是指针
{
	int sz2 = sizeof(arr) / sizeof(arr[0]);
	printf("sz2 = %d\n", sz2);
}
void test2(int* arr) //参数写成指针形式
{
	int sz3 = sizeof(arr) / sizeof(arr[0]);
	printf("sz3 = %d\n", sz3);
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz1 = sizeof(arr) / sizeof(arr[0]);
	printf("sz1 = %d\n", sz1);
	test1(arr);
	test2(arr);
	return 0;
}

代码运行结果如下:
C语言之深入指针(二)(详细教程)_第2张图片

1.数组名是数组⾸元素的地址;那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参本质上传递的是数组⾸元素的地址
所以在函数中是无法计算数组的元素个数的
2. 其次,一维数组的传参,函数的参数可以写成数组的形式,也可以写成指针形式

你可能感兴趣的:(初识C语言,c语言,算法,开发语言,学习,笔记,经验分享)