c语⾔指针实验的⼼得,关于C语⾔指针的⼀些学习⼼得(⼀)1.⾸先理解⼀些内存。
就跟要去电影院看电影⼀样,电影院⾥⾯有座位,座位编号。⼈才能坐。内存也类似于电影院⾥的座位,值不够内存是⼀个存放数据的空间。我们在内存中存放各种各样的数据。当然我们 要知道我们的这些数据存放在什么位置吧!所以内存也要象座位⼀样进⾏编号了,这就是我们所说的内 存编址。座位可以是按⼀个座位⼀个号码的从⼀号开始编号,内存则是按⼀个字节⼀个字节进⾏编址, 每个字节都有个编号,⼀个字节代表⼋位。关于各种数据类型占有的字节数在其他篇幅中有说明。内存空间的布局类似于下图所⽰。注意是按照⼀个字节⼀个字节来编址的。
2.C语⾔中变量的声明。
int a;
char b;
每次我们要使⽤某变量时都要事先这样申明它,它其实是内存中申请了⼀个名为i的整型变量宽 度的空间(4字节),和⼀个名为a的字符型变量宽度的空间(1字节)。⽐如说,a申请的内存从6开始,则6,7,8,9都将被a预订,⽤于存放a的数据。⽽10将被b预订,⽤于存放b的数据。此时a和b只是个变量,并没有确切的值。但是内存已经分配了。只要声明就会分配。如下图所⽰。
3.变量赋值。
若进⾏赋值
a=10;
b='t';
则内存空间变成这样。
当然具体存放的可能是⼆进制的,并不是10 和‘t'。
这⾥需要注意的是,⼀个局部变量在声明的时候就已经开辟了内存空间。如果没有赋值的话,它的值是不确定的。如果有下⾯⼏⾏代码。得出的结果是这样的。
#include "stdio.h"
int main()
{
int i;
long a;
char c;
char d;
printf("%d,%d,%d\n",i,&i,sizeof(i));
printf("%d,%d,%d\n",a,&a,sizeof(a));
printf("%d,%d,%d\n",c,&c,sizeof(c));
printf("%d,%d,%d",d,&d,sizeof(d));
return 1;
}其结果是:
观察结果可以知道,i和 char的值都是不确定的。但是i的开始地址是1244996,⽽a的开始地址是1244992。因为i和a的内存空间都是在栈中开辟的,在栈中的内存空间是从⼤往⼩⾛的。
可能有⼈会疑惑为什么d的内存开始的时候是84,它只占⼀个字节,按理说c应该从89开始,c同样占⽤⼀个字节,则a应该从90开始。事实上却不是,不管是c,还是d内存都给他们分配了4个字节。这是字节对齐的原因,关于字节对齐,会另开贴讨论。现在只需知道,对于32位的机器,默认为4字节对齐。
4.指针
指针其实也是⼀个变量,可以这样说,它跟其他变量其实没啥区别。关键的是,这个变量所代表的内容是什么?对了,这个变量所表⽰的内容是⼀个地址。但是说实在的,地址其实就是类似与⼀个int型的数。所以指针这种变量都是占4个字节的。
#include "stdio.h"
int main()
{
int i;
//long a;
//char c;
//char d[6];
int *p=&i;
printf("%d,%d,%d\n",i,&i,sizeof(i));
//printf("%d,%d,%d\n",a,&a,sizeof(a));
//printf("%d,%d,%d\n",c,&c,sizeof(c));
//printf("%d,%d,%d\n",d[0],d,sizeof(d));
printf("%d,%d,%d,%d",*p,p,&p,sizeof(p));
return 1;
}
我们运⾏上述代码,则可以很清楚的得到下⾯结果。
说明这个指针的值就是i变量的地址,(就如同int a=3, a的值是3.只不过这时候变量不是i,是⼀个指针p。)这⾥就需要注意了:p是⼀个变量,p的值是⼀个地址,(相当于说i是⼀个变量,i的值是3),⽽p的地址则是另外⼀个值了(就是&p)。⽽p的值(这个地址),⾥⾯还装着⼀些东西。(本例中就是i的值。)这才是我们研究的关键。所以,指针p是⼀个地址,它指向了⼀个变量。这个变量可以是任何类型的变量。但是指针的值只能是⼀个地址。
归纳起来就是,指针也是⼀个变量,这个变量的值是⼀个地址,这个地址是另外⼀个变量的地址(也就是该指针所指向的变量的地址)。
5.指针类型
从语法的⾓度看,只要把指针声明语句⾥的指针名字去掉,剩下的部分就是这个指针的类型了。如:
int *ptr;//去掉ptr,指针类型是int*
char*ptr;//去掉ptr,指针的类型是char*
int**ptr;//去掉ptr,指针的类型是int**
int(*ptr)[3];//去掉ptr,指针的类型是int(*)[3];
int*(*ptr)[4];//去掉ptr,指针的类型是int*(*)[4]
这个int*ptr[3],ptr并不是⼀个指针,⽽是⼀个数组,因为【】的优先级⼤于*所以ptr[3]是⼀个数组,然后与int*结合,说明这个数组⾥⾯的元素是3个指针。这3个指针指向int型变量。
6.指针所指向的类型。
当你通过指针来访问指针所指向的内存区时,
指针所指向的类型决定了编译器将把那
⽚内存区⾥的内容当做什么来看待。
从语法上看,你只须
把指针声明语句中的指针名字和名字左边的指针声明符*去掉,
剩下的就是指针所指向的类型。
例如: 当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那⽚内存区⾥的内容当做什么来看待。
从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:
sizeof 指针int*ptr; //去掉*ptr,指针所指向的类型为int.
char*ptr; //去掉*ptr,指针所指向的类型是char.
int**ptr;//去掉*ptr,指针所指向的是⼀个int*的指针,设为p,则该p指针指向的是⼀个int的类型
int(*ptr)[3]//指针指向的是int()[3](其实就是int[3])是⼀个数组,⽽且这个数组的元素有3个,元素时整型的。
int*(*ptr)[4];//指针所指向的类型是int*()[4],这是⼀个数组,数组⾥⾯的元素是4个指针,⽽且4个指针指向的类型是整型。
7.指针的值--也就是指针所指向的地址
指针的值是指针本⾝存储的数值,这个值将被编译器当作⼀个地址,⽽不是⼀个⼀般的数值。在32位程序⾥,所有类型的指针的值都是⼀个32位整数,因为32位程序⾥内存地址全都是32位长。指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为
sizeof(指针所指向的类型)的⼀⽚内存区。以后,我们说⼀个指针的值是XX,就相当于说该指针指向了以XX为⾸地址的⼀⽚内存区域;我们说⼀个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的⾸地址。指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例⼀中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是⽆意义的。
以后,每遇到⼀个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪⾥?(重点注意)
8指针本⾝所占有的区域。
上⾯已经讲过,指针占有4个字节。只要⽤seizeof(指针的类型)或者sizeof(指针)即可以。
9.指针的算术运算
⼀句话:
⼀个指针ptrold加(减)⼀个整数n后,结果是⼀个新的指针ptrnew,ptrnew的类型和ptrold的类型相同,ptrnew所指向的类型和ptrold所指向的类型也相同。ptrnew的值将⽐ptrold的值增加(减少)了n乘sizeof(ptrold所指向的类型)个字节。就是说,ptrnew所指向的内存区将⽐ptrold所指向的内存区向⾼(低)
地址⽅向移动了n乘sizeof(ptrold所指向的类型)个字节。
⽐如以下例⼦:
#include "stdio.h"
int main()
{
char a[20]="You_are_a_girl";
char *p=a;
char **ptr=&p;
printf("%d,%d\n",a,&a);
printf("p=%d\n",p);
printf("&d=%d\n",&d);
printf("ptr=%d\n",ptr);
printf("*ptr=%d\n",*ptr);
printf("**ptr=%c\n",**ptr);
ptr++;
printf("ptr=%d\n",ptr);
printf("*ptr=%d\n",*ptr);
printf("**ptr=%c\n",**ptr);
return 1;
}
打印出来的结果是:
从上述的结果可以看出,ptr是⼀个指向指针P 的指针,是⼀个⼆级指针,ptr的类型是char*,当ptr+1
的时候,偏移量应该是sizeof(char*);应该是4.这样以后,ptr所指向的位置是不⼀定的。所以这时候的**ptr也是⼀个不确定的值。
10.⼀些需要注意点
⼀个例⼦
#include"stdio.h"
int main()
{
char *a[4]={"China","French","American","Japan"};
char**p=a;
printf("%d,%d,%d,%d,%d,%d\n",a,&a,&a[0],&a[1],&a[2],&a[3]);
printf("sizeof(a)=%d\n",sizeof(a));
printf("%d,%d,%d,%d\n",a,a+1,a+2,a+3);
printf("%d,%d\n",&a,&a+1);
printf("%d,%d,%d,%d\n",*a,*(a+1),*(a+2),*(a+3));
printf("%d,%d,%d,%d\n",a[0],a[1],a[2],a[3]);
printf("%s,%s,%s,%s\n",a[0],a[1],a[2],a[3]);
printf("%s,%s,%s,%s\n",*a,*(a+1),*(a+2),*(a+3));
printf("%c,%c,%c,%c\n",*a[0],*a[1],*a[2],*a[3]);
printf("%s,%s,%s,%s\n",p[0],p[1],p[2],p[3]);
printf("%s,%s,%s,%s\n",*p,*(p+1),*(p+2),*(p+3));
return 1;
}
这个例⼦的结果是
通过这个例⼦,我们对⼆级指针,char*a[4]这种类型应该有更加深⼊的了解。
这是⼀个数组,数组的元素是4个char*指针,char*指针是指向⼀个数组的(或者说指向⼀个char*串),所以其实这是⼀个⼆维数组。
第⼀个问题:a的size是多少?
因为a是⼀个数组,所以,他的⼤⼩应该等于数组的维数4乘以元素的⼤⼩,⽽数组的元素如上所说,是char*的指针,所以⼤⼩应该是4乘以4=16.
第⼆个问题:a,a+1,a+2,a+3.
因为a,是⼀个数组,所以数组名a代表的是第⼀个元素的地址,也就是&a[0],同样的a+1是指向第⼆个元素的地址。他们之间的偏移量应该是4.同样的,&a[0],&a[1]与a,a+1是⼀样的。注意,这是元素的地址,并不是元素的值。
第三个问题:*a,*(a+1)是什么。
a是⾸元素的地址,那么*a就是第⼀个元素的值,同样的*(a+1)是第⼆个元素的值。以此类推。元素的值,还是⼀个地址,只不过这四个地址没有必然的连续关系。a[0]与*a,a[1]与*(a+1)是⼀样的。
第四个问题,如何打印⼀个字符串。
在C语⾔中,其实没有字符串这个概念。可以⽤两种⽅法来表⽰字符串,⼀种是使⽤数组如char a[]=”china",这时候打印字符串只需要printf("%s",a),因为a是⼀个指针。或者另外⼀种⽅法,定义⼀个c串,如char*a1="china“.打印⽅法是⼀样的printf("%s",a1)。不过需要注意的sizeof(a)和sizeof(a1)是不⼀样的,第⼀个是数组的长度,⽽第⼆个是⼀个指针的长度。此处还要注意,字符串数组的结束符是占有直接⼤⼩的。他占了⼀位。所以sizeof(a)应该是为6。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论