上一篇博客给大家讲了一部分的指针,指针的内容很多但也很重要,SO现在继续!希望大家多多支持!
下面我们先看一段代码:
#include
int my_strlen(const char* str)
{
int count = 0;
assert(str);
while (*str)
{
count++;
str++;
}
return count;
}
int main()
{
int len = my_strlen("abcdef");
printf("%d\n", len);
return 0;
}
这是一段模拟库函数strlen的代码实现,代码中就将字符串的首个字符指针传给了函数,进而完成代码的实现。
接下来我们再看一段Swap函数的代码:
#include
void Swap1(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int i = 0;
int j = 0;
scanf("%d %d", &i, &j);
printf("交换前:a=%d b=%d\n", i, j);
Swap1(i, j);
printf("交换后:a=%d b=%d\n", i, j);
return 0;
}
不难发现其实 i 和 j 的值并未发生转换,这是为什么呢,我们继续往下看:
通过监视窗口我们发现虽然 i,j 的值与x,y的值对应相等但他们的地址却不相等,这是为什么呢?因为x和y确实接收到了a和b的值,不过x的地址和a的地址不 ⼀样,y的地址和b的地址不⼀样,相当于x和y是独立的空间,那么在Swap1函数内部交换x和y的值, 自然不会影响a和b,当Swap函数调用结束后回到main函数,a和b的没法交换。Swap函数在使用 的时候,是把变量本身直接传递给了函数,这种调用函数的方式我们之前在函数的时候就知道了,这 种叫传值调用。
所以我们得出一个结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参。 所以Swap是失败的了。
所以我们就需要运用到指针的传址调用了!我们只需要把 i 和 j 的地址传给函数即可:
#include
void Swap1(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
int main()
{
int i = 0;
int j = 0;
scanf("%d %d", &i, &j);
printf("交换前:a=%d b=%d\n", i, j);
Swap1(&i, &j);
printf("交换后:a=%d b=%d\n", i, j);
return 0;
}
我们可以看到实现成Swap的方式,顺利完成了任务,这⾥调⽤Swap2函数的时候是将变量的地址传 递给了函数,这种函数调用方式叫:传址调用。
结论:传址调用,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量;所 以未来函数中只是需要主调函数中的变量值来实现计算,就可以采⽤传值调用。如果函数内部要修改 主调函数中的变量的值,就需要传址调用。
数组名和指针有啥关系呢?我们看下面代码:
#include
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("&arr[0] = %p\n", &arr[0]);
printf("arr = %p\n", arr);
return 0;
}
我们发现数组名和数组首元素的地址打印出的结果⼀模⼀样,数组名就是数组首元素(第⼀个元素)的地址。但需要注意的是在两种情况下这两个还是有所区别的:
下面给大家展示代码理解一下:
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", sizeof(arr));
return 0;
}
我们可以看到这里显示40个字节,SO这里就印证了上面的说法·
下面我们在思考一下,下面的代码:
#include
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("&arr[0] = %p\n", &arr[0]);
printf("&arr[0]+1 = %p\n", &arr[0] + 1);
printf("arr = %p\n", arr);
printf("arr+1 = %p\n", arr + 1);
printf("&arr = %p\n", &arr);
printf("&arr+1 = %p\n", &arr + 1);
return 0;
}
是不是发现其中的奥妙了呢!
&arr[0] = 004FFC14 数组首元素地址
&arr[0]+1 = 004FFC18 第二个元素的地址
arr = 004FFC14 数组首元素地址
arr+1 = 004FFC18 第二个元素的地址
&arr = 004FFC14 数组首元素地址
&arr+1 = 004FFC3C 跳过整个数组的地址
这里我们就需要注意一个问题了:
#include
void test(int arr[])
{
int sz2 = sizeof(arr) / sizeof(arr[0]);
printf("sz2 = %d\n", sz2);
}
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);
test(arr);
return 0;
}
可已看出我们将数组传到函数时此时arr是一个地址所以其大小只能是4(在32位机器中)所以
sizeof(arr) / sizeof(arr[0]) 的值为1。
二级指针也称为指向指针的指针,是指针的指针,即指针变量的值是指向另一个指针变量的地址。
我们知道指针变量也是变量那么,变量就会有地址,那么二级指针便是用来储存指针的地址。
#include
int main()
{
int a = 10;
int* p = &a;
int** pa = &p;
printf("%p %p", p, pa);
return 0;
可以看出地址确实是存在的。
我们可以联想到之前,整型数组,是存放整型的数组,字符数组是存放字符的数组。 那指针数组呢?那当然是存放指针的数组了。
看了上图是否清晰明了了呢!!!
最后我们来讲一下:指针数组模拟二维数组
代码的实现可以看下面的代码:
#include
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
//数组名是首元素地址,类型是int*的,就可以存放在parr数组中
int* parr[3] = { arr1, arr2, arr3 };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
这样我们就可以用指针数组模拟出一个二位数组了。
好了今天到此结束!喜欢的可以三连加关注哦!