p是一个变量,那么想怎么给它赋值,就可以怎么给它赋值,但是C语言是强类型语言,如果赋值类型不匹配就会报错,如果赋值类型虽然不匹配但是可以默认转换,那么编译可以通过但是会给警告。
比如可以这样做:
p = 0;
p = 1;
都没问题,因为p是一个指针,数字类型可以赋值给指针,但是给它赋值是什么含义?含义不对,即使编译通过,运行也会报错的。
在第一个文件里存在一个错误是i没有初始化,必须初始化为0或者1或者什么数字,不然一定会出错,下面的讨论假设初始化为1:
在第一个文件里面,p是一个变量,这个变量的类型是指针,这个指针所指向的是“字符串指针”。
那么既然是变量,就可以读和写,所以可以赋值;由于是强类型,所以只要是指针类型或者能转换成指针类型的就可以赋值;由于它是一个指向”字符串指针“的指针,所以给它赋值的时候,如果所赋值对象类型不是指向”字符串指针“,一般编译器都会提示一下的。
name也是一个变量,这个变量的类型也是指针,这个指针所指向的是”字符串数组“。在C语言里面,数组其实就是指针,但是是常量,不能写,只能读,所以name这个变量可以读可以写,但是它指向的内存因为是常量数组所以只能读不能写,除此以外name和p没有任何区别。
因此,name + i是指针加法,name + i还是一个指针,指向字符串数组,只不过所指内容和name不一样,是name的”下一个“,所以p = name +i 属于两个同类型指针赋值,没有任何问题;
p=name[i]和p = name + i是不一样的,name定义为一个数组,name[i]是取数组的第i个元素,相当于(name + i)。(感谢 @单车恋人 指正)但是这个赋值还是会成功的,因为p是指向字符指针的指针,本质还是一个指针,name是一个字符指针的数组,取出的第i个元素是一个字符指针,赋值可以成功,但是类型不一样(字符指针的指针和字符指针)。
p=name+i 性质就变了,就是把name所指向的内容加1,然后赋值给p,name作为一个指针指向的是 字符串数组,还好字符串数组也是指针(指针与数组在C语言里面都按照指针处理),所以赋值可以成功,但是会给出编译警告,因为毕竟他们不是相同类型,p是指向指针的指针,赋值内容是数组,相当于指针。
p=name+i 在这里name + i和前面的分析一样,它和p是相同类型,是指针的指针;而p是一个指针了,这时候要把它赋给p还是指针之间的赋值,编译可以通过,但是指针类型不同,也会给出编译警告。这里要注意,p是一个变量没问题,但是p能不能赋值取决于p指向的空间,如果p指向一块可读不可写的内存,程序运行到这里会运行时退出;如果p指向一块可写的内存而且有足够的空间,那么就没问题。
抱歉第二个文件就不这样详细分析了,没想到这么长太累了,不过思路是类似的。写了段代码供参考,用的是64位Linnux下Gcc编译器,所以打印指针的时候转换成long类型,如果是32位转换成int类型,这里p指向的是一块不可写内存,所以在*p = name + i那里会运行时报错:
include "stdio.h"
int main()
{
char *name[]={"abc","edf","ghi"};
char *p;
int i = 1;
p = name[i];
printf("%ld\n", (long)p);
p = name + i;
printf("%ld\n", (long)p);
p = name + i; /此处执行会出错/
printf("%ld\n", (long)p);
/*
int a[4]={1,3,5,7};
int (*p)[4];
p = 0;
p = &a;
printf("%ld\n", (long)p);
p = a;
printf("%ld\n", (long)p);
printf("%ld\n", (long)*p);
printf("%ld\n", (long)**p);
*/
}