关于指针

首先,要写这篇文章的原因非常之惭愧,在看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 = "abcdefg",则打印结果为abc。

最后补充一点,对于一个指针变量char *p, &p表示该变量自身的地址,p表示其保存的内容,*p表示将其内容作为一个地址读取其内容。如果其内容为未分配内存的地址,则会导致系统崩溃。

原文地址:https://www.cnblogs.com/scu-cjx/p/7922881.html