首先,要写这篇文章的原因非常之惭愧,在看do_fork实现的源码中,有如下(部分代码省略):
do_fork:
struct task_struct *p;
p = alloc_task_struct();
*p = *current;
从代码上看很清晰,声明指针p,分配两个物理页内存,然后把当前进程的task_struct内容复制给p。本来都已经跳过了,但突然想到从来都是赋值地址,或者是strcpy的方式,还没有这样写过,然后打开编译器试了一下,结果就牵扯出了一堆问题,不过现在搞清楚了。总结如下:
版本1:
int main() { char *s = "abcdefg"; char *a = NULL; a = s; printf("%s ", a); return 0; }
平时常用该方法,输出结果:
abcdefg
版本2:
int main() { char *s = "abcdefg"; char *a = malloc(sizeof(char) * 8); strcpy(a, s); printf("%s ", a); return 0; }
平时常用该方法,输出结果:
abcdefg。
版本2与版本1不同的地方在于,在2中为a动态分配了8个字节内存(包含 ),然后strcpy将s指向的内存单元中的字符串拷贝到a指向的内存单元,如果不动态分配内存,则a指向非法地址,strcpy导致程序崩溃。
版本3:
主要是对某些理论进行了验证。首先一个需要明确的概念为,任何一种类型的指针变量只与系统架构有关,即32位操作系统为4字节,64位操作系统为8字节,表明可以寻址的大小(当然这样的说法不全对,还与编译器等因素相关,但总之想表明与char *p, int *p的类型无关,这个概念差点都忘了)。先贴代码:
int main() { char *s = "abcdefg";; printf("%p ", &s); printf("%p ", s); return 0; }
输出结果:
%p显示指针地址,与%#x类似。可以看到指针s所在的内存单元,地址为0x0060ff08,其保存了地址0x00403024(指针的本质)。
版本4:
之后我针对上述地址进行了测试。代码如下:
int main() { char *s = "abcdefg";; printf("%p ", &s); printf("%p ", s); printf("%c ", *s); printf("%s ", 0x403024); printf("%s ", 0x403025); printf("%c ", *(char *)0x403026); return 0; }
输出结果:
可以看到c语言中的字符串,对于编译器而言保存的为地址,而且是字符串首字母的地址,我们看到的是char *s = "abcdefg",实际上保存的为 char *s = 0x403024 0x403025 ……,而char型的指针,指明了每个元素占用的内存大小为一个字节,即24中保存a,25中保存b,如果为int型指针,每个元素占用大小应该为4个字节。
图示为:
而且在printf一个字符串时,字符串默认以 结尾,所以在遇到 是系统判断字符串结束,所以如果上述代码改为char *s = "abc defg",则打印结果为abc。
最后补充一点,对于一个指针变量char *p, &p表示该变量自身的地址,p表示其保存的内容,*p表示将其内容作为一个地址读取其内容。如果其内容为未分配内存的地址,则会导致系统崩溃。