本人小白,本文专门给初学者准备,大神自动跳过。
不喜勿喷,谢谢。
如有错误,请指正,谢谢。
正文:
进来有人问我一些有关于指针的问题。在此我贴出问题
问题如下:
char *msg[5] = {"Thank you","You are"};
mian()
{
printf("%s",msg[0]);
}
问题一:为什么msg[0]可以输出Thank you?
问题二:如果把msg看成是二维数组的名字,那msg[0]不应该是Thank you 的首地址么?
问题三:用%s这个可是可以输出地址里的内容么?
问题四:如果用msg可以输出Thank you 么?*msg呢?
解答:
首先我们来看看我们定义的是什么吧
我们定义的是char *msg[5]; 这是代表我们定义了一个数组,数组名叫msg,数组包含了5个元素,这些元素的类型是char *类型,很明显这些元素是指针
也就是说我们定义了一个指针数组,我们这个数组就是保存了一些地址而已
而且我们在定义的时候,是对这些元素(指针)进行了初始化了的。
msg[0]这个指针存放了“Thank you”这个字符串的首地址,msg[1]这个指针存放了“You are”这个字符串的首地址。
另外我们知道%s是只要我给了一个地址,它就能完整的输出字符串
所以我们在输出的时候传入了一个msg[0],也就是传入了一个地址,这是“Thank you”的首地址。自然而然计算机就能输出完整的Thank you
至于我们能不能将msg看成二维数组的名字呢?我们之后讨论,我们先说最后一个问题
用msg能不能输出Thank you呢?答案是不能
用*msg能不能输出Thank you呢?答案是能
我们来看一下这两者的区别
1. 一个数组的名字在C/C++中,如果没有特别说明,那么它就代表的是一个指针,这个指针指向这串数组的首个元素的地址
那么我们在调用msg的时候,电脑默认我们给了一个msg[0]的地址,也就相当于msg = &msg[0]
所以我们在用%s输出msg的时候,实际上我们就是传入了一个msg[0]的地址,那msg[0]是什么?是指针啊!!!不是字符串啊!!!
所以用msg的时候就不能正确输出
2. 那么第二个呢?*msg又如何呢?
前面一种情况我们已经介绍了msg表示msg[0]的地址。那么当我们使用*msg的时候,它就指向了msg[0]中的内容。因而*msg = msg[0]
那msg[0]存放了什么?存放了“Thank you”的首地址!!!
所以我们在用%s输出*msg的时候是可以正确输出的
最后我们再来看看我们能不能将msg看成是二维数组的名字呢?
我的理解是可以的,虽然不严谨,但是在大部分使用上我认为我可以替换的
这里我们先不讲枯燥的理论知识,我们先来介绍一下如何用动态内存分配去搞出个二维数组
int i;
char **p; //定义一个指向指针的指针(好绕口……)
p = (char **)calloc(5,sizeof(char*)); //先分配最外层的内存,这里我们可以看到我们是分配了5个char*类型的内存,也就是我们打算在这里放5个指针
for(i = 0; i < 5; i++)
(*p) = (char *)calloc(10,sizeof(char));//在分配最内层的内存,也就是我们用来存放“Thank you”的内存
这很经典,仔细观察我们可以发现这和我们上面提到的char *msg[5]很像,不同的是char *msg[5]没有定义最内层的东西,只有最外层的指针。
一个是一维数组,一个是二维数组。虽然定义不一样,但是本质上没啥大区别,我们用它们实现的功能都差不多
所以我说可以看成是二维数组的名字