征服C指针(讲那么复杂,中国人永远都别想超越美国人)
一段永久掉坑的代码
#include <stdio.h>
void one_set(int num)
{
num = 11;
}
void two_set(int *num) //掉坑一,蒙圈
{
*num = 11; //掉坑二,泪奔
}
int main(void)
{
int one = 1;
int two = 2;
one_set(one);
two_set(&two); //掉坑三,又掉坑,没得救啦
printf("one = %d; two = %d\n", one, two);
return 1;
}
保存为demo.c 运行gcc -g demo.c -o demo然后执行./demo 输出结果是
one = 1; two = 11
结果没有错误,为什么掉坑
掉坑一:形参到底表示什么意思?two_set函数样子跟one_set一样,能看出区别吗?
大神说:不是有星号吗?看得出来是传入内存地址,不想跟傻逼聊天了!
我回复:那为啥你写的代码,不写成 void two_set(int* num) 更好
掉坑二:这赋值语句是啥?num就是普通数字,前面加个星号,是搞笑的吗?
大神说:指针的意思呀,num的指针指向11,用屁股想想都明白!
我回复:那为啥你写的代码,不写成 *addr = 11; 更好
掉坑三:我去,我就喜欢实参传入two,你就偏偏写成&two,气死人!
大神说:&这个符号,不懂就去学呗
我回复:我就偏偏不学,我要换另一种写法
与大神对话后,我换了另一种写法
#include <stdio.h>
void one_set(int num)
{
num = 11;
}
void two_set(int* addr) //掉坑一,蒙圈
{
*addr = 11; //掉坑二,泪奔
}
int main(void)
{
int one = 1;
int two = 2;
int* twoAddr = &two;
int threeAddr[] = {1,2,3};
one_set(one);
two_set(twoAddr); //掉坑三,又掉坑,没得救啦
two_set(threeAddr);
printf("one = %d; two = %d\n", one, two);
printf("three[0] = %d; three[1] = %d\n", threeAddr[0], threeAddr[1]);
return 1;
}
保存为demo.c 运行gcc -g demo.c -o demo然后执行./demo 输出结果是
one = 1; two = 11
three[0] = 11; three[1] = 2
解释为什么这样子写
- 变量加上Addr表示是地址的意思,two_set函数内容表达的意思特别清晰,即传入地址指向数字11。
- 书本表示数组,喜欢用arr[] = {1,2,3}。通过该代码threeAddr对比,发现书本上arr其实是地址的意思。
- 另外惊讶发现,two_set函数居然可以用于int和int数组,测试结果可以改变threeAddr数组第一个元素为11。
- 得出来结论:threeAddr数组是有连续3个地址,第一个地址是threeAddr,指向数字1。从而明白了内存结构。
*threeAddr | threeAddr [0] | 1 |
---|---|---|
*(threeAddr+1) | threeAddr [1] | 2 |
*(threeAddr+2) | threeAddr [2] | 3 |