C语言指针基础(1)

来源:互联网 发布:毕业摄影的数据 编辑:程序博客网 时间:2024/06/05 21:28

C语言作为一门毅力几十年不倒的计算机语言,深受编程爱好者的喜欢。但是,许多人学习c语言(不管是计算机专业的,还是其他专业的),都会觉得C语言中的指针最难,甚至会因此放弃了c语言。但是,指针真的有那么难吗?下面就从这段代码开始我们的指针基础学习。

void main(){     int a = 10;    int b = 20;    int *p = &a;//p指向了a    int *q = &b;//q指向了b    *p = 11;//通过指针p修改了a的值    *q = 21;//通过指针q修改了b的值    a = 12;//直接修改    b = 22;//直接修改    printf("a = %d,b = %d\n",a,b);//12    printf("*p = %d,*q = %d\n",*p,*q);//22}

上面代码展示的就是通过变量名直接修改对应的内存的值和通过指针间接的修改内存的值。到这,可能很多人都会觉得很明白,没有疑惑。但是,我在注释中写的 “p指向了a” 这句话,你真的明白吗。看下面这张图:

这里写图片描述

在这张图中,我们可以看到变量p中存储着变量a的地址(类似于int a = 1,变量a存储着1);而这就是关键,所谓p指向a,就是指p所在的内存存储着a所在内存的地址。指针指向谁,就把谁的地址给它。另外,变量名p或a只是所在内存的别名而已。而对于指针变量与普通变量之间的差别,我们也就可以就此得出:指针变量与普通变量都只是一块内存的别名而已,只是指针变量的值是地址而已。

但事实上,上面的代码没有任何意义。为什么呢?我们明明可以直接用a等于多少来改变内存中的值,为什么还的绕一圈,用指针来修改呢。没错,在这,这就是多余的。指针最大的意义其实是作为函数指针。很多人在一个代码块中知道怎么用指针,但一旦指针到了另一个函数作为函数参数,就瞬间不知该去哪了。下面就从这段代码看看怎么用。

#include<stdio.h>#include<stdlib.h>#include<string.h>int copy_str(char *sou,char *des){    int res = 0;    if(sou == NULL || des == NULL)//先做指针是否为NULL的判断    {        res = -1;        printf("copy_str err : %d  NULL",res);        return res;    }    while(*sou != '\0')    {        *des = *sou;        sou++;        des++;    }    //到这说明此时*sou == '\0'    *des = '\0';//des也得加'\0',表示字符串结束    return res;}void main(){     char buf1[100];    char buf2[100];    int res = 0;    //这句话的意思是针对buf1所指向的内存全部赋值为0    memset(buf1,0,sizeof(buf1));    memset(buf2,0,sizeof(buf2));    strcpy(buf1,"cpy_str test");    res = copy_str(buf1,buf2);    if(res != 0)    {        //err         return;    }    printf("%s",buf2);}

这段代码的主要功能就是拷贝字符串。C语言用字符串数组表示字符串。
下面就对这段代码进行详细的讲解。

首先,我从 “char buf1[100]”这句代码开始,可能很多人会直接跳过了这句,但事实上,这句话很重要,不了解这句话,就看不懂copy_str函数的参数。
chat buf1[100],表示在内存(栈)中分配100个字节的内存,而buf1表示这100字节个内存中首个字节的地址,假设chat buf1[100] = “asdqwe”;那么buf1就是表示‘a’的地址,打印buf1[0],就会得到‘a’显示。打印buf1[1],就会得到‘s’显示…… 值得注意的是,“asdqwe”其实在内存中全局区(常量区),是字符串常量初始化数组,它自动会在最后一个字符‘e’的后面加’\0’,表示结束,这也意味着buf[6] == ‘\0’。

在看int copy_str(char *sou,char *des)这个函数。我们是copy_str(buf1,buf2); 这样调用的。这句话的意思是sou = buf1,des = buf2;但这不够。我们得用内存的角度去思考,再画一个图:
这里写图片描述

这里可以想象成sou和des两个指针分别指向了buf1和buf2两个指针指向的内存(注意:数组名也是指针),我们要从内存的角度思考,两个指针都指向一片内存,我们不管通过*sou还是*buf1都是操作那片连续内存,可以说sou与buf1并没有什么关系,改变的都是那片内存。另外由于sou已经指向了buf1的那片内存的首地址。就可以通过*sou改变内存中的值。des也是如此。

再看 if(sou == NULL || des == NULL) 这句,我做了个小判断,如果sou或者des的值(指针变量的值就是指向的内存地址)为NULL,说明指针并未指向一片内存,没有内存的指针,毫无用处。*sou也根本没有意义,因为根本就没有内存让指针操作。

再看
while(*sou != ‘\0’)
{
*des = *sou;
sou++;
des++;
}
这句,刚开始sou指向的buf1那片内存的首地址,也就是首个字节的地址,先判断首个字节的值是否为’\0’,不是的话说明字符串未结束。
将sou指向的内存的值,赋值给des指向的内存的值(buf2那片内存的首地址的值,就是*des)。也就是这个函数最主要的copy功能。

再关注sou++,表示sou指针的指向+1,也就是从第一个字节的地址,移动到了第二个字节的地址,值得注意的是指针的步长取决于指针类型。这里是char,也就是一个char1个字节,也意味着步长+1就是移动1个字节。des++一样。

到了循环的第二次还是先判断是否到底,再赋值,移动。直到碰到内存中的值为’\0’。

再看这句,
//到这说明此时*sou == ‘\0’
*des = ‘\0’;//des也得加’\0’,表示字符串结束

此时,*sou == ‘\0’,表示到了原字符数组的末尾,此时也需要给des此时指向的内存赋值’\0’;也表示这个字符串结束了。

这就是今天的C语言指针基础,可能第二个例子对初学者有点难,但是通过字符串练习一级指针真的是非常管用。另外,画图,也是非常重要的。你画的出来,才说明你真的了解指针背后的内存。指针一定要和内存配合。没有内存就没有指针。

0 0
原创粉丝点击