C语言里面的指针问题

来源:互联网 发布:文华财经mac版 编辑:程序博客网 时间:2024/05/17 16:13


一、变量与指针


1.变量


C语言中每次声明一个变量,则内存在会申请一个该变量类型应该占据的空间.


假设int类型占四个字节(不同系统的字节数不同),那么语句


int a;


a=10;


即在内存中申请了四个字节的空间,并将其命名为a,其值为10.


 


2.变量地址


int型变量a在内存有一个具体的地址编号,用 &a 可以读取到,如print(“%d,&a;即可打印出变量a的内存地址编号。


 


3.指针变量


指针其实也是一种变量,语句 int* pointer即在内存中申请了int类型变量的空间,将其取名为pointer.


它和之前的a其实没有本质不同。区别在于,pointer的内容是某个int变量的地址。


pointer = &a即把变量a的地址赋给pointer


那么通过语句printf(“%d”,*pointer)即可打印出a,这里*pointer即为按照pointer的内容寻址,得到的具体变量内容。


这里pointer里面存的是a的地址,那么按照该地址寻找就得到变量a了,*pointer就显示出a的内容,即为10


 


4.思考


假设给出这样一段代码:


int a, *pi;


a = 10;


pi = &a;


*pi = 20;


printf("%d", a)


那么打印出的a值是多少?20


 


二、数组与指针


1.C语言中定义一个数组,那么数组名实质上是个指针"常量",比如


int a[]={1,2,3,4};


printf("%d",a); //得到的是内存位置


printf("%d",*a); //得到第一个元素


printf("%d",*(a+1));  //得到第二个元素


那么打印a得到的就是数组第一个元素所在的内存编号位置,打印 *a 得到的就是1


需要注意的是打印*(a+1)得到恰好是第二个元素,因为a是指针变量,加1其实是加一个int类型的宽度


所以 a+1得到的是后一个元素的位置,从而 *(a+1)即可得到第二个元素。


 


再者,a是一个常量,若使用 a++ 这样的赋值语句会出现编译报错。


不过可以将a的值赋给一个指针变量pi,从而就可以使用 pi++ 这样的语句进行遍历:


int i, *pi, a[]={1,2,3,4}


pi = a //a的值赋给pipi就记录了数组的起始位置


for(i=0;i<4;i++)


{


 printf("%d\n", *pi);


 pi++;   //这两句语句也可以用printf("%d", pi[i])代替,其中pi[i]a[i], *(pi+i), *(a+i)等价


}


以上代码就依次打印出了数组a的元素,循环里的pi不能用a代替。


 


2.指针常量


除了指针变量,我们也可以声明一个指针常量,如下:


int i, a[]={1,2,3,4}


int * const pi = a //注意const的位置


此时pi就无法进行1中的遍历,因为此时pi已经是个常量了。


需要注意的是一般定义数组时:


int * const a ={1,2,3,4} //这样不行


int a[] = {1,2,3,4} //可以,一般定义数组的方式


 


3.const关键字与指针


const修饰过的变量不能进行重新赋值,如:


const int ic=20; //这句等价于int const ic = 20intconst哪个放前面都可以


ic = 40 //这句编译会出错


那么const修饰指针变量时,会出现 const int * a, int const * a, int * const a 这三种情况,其实前两种等价;


 


首先看 const int * pi,这里const修饰的是*pi,所以不能对*pi直接重新赋值,但是pi所指向的那个变量可以重赋值


int a = 10;


int b = 20;


const int *pi = &a


pi = &b //pi是可以重赋值的,const修饰的是整个 *pi


b = 40; //这里可以用 *pi=40 来更新值吗?不行,const修饰了*pi


printf("%d",*pi); //得到的是40


这里 pi还是可变的,只是不能直接对 *pi进行修改,那么如果想让 pi无法更改怎么办呢?这对应第三种情况。


 


对于 int * const pi,这里 pi 是个常量了,不能重新赋给它另外一个地址值,但是此时可以对 *pi重赋值


int a = 10;


int b = 20;


int * const pi = &a;


//pi = &b是错的,pi无法再指向另外一个地址


a = 80 //这里可以用*pi = 80来代替


printf("%d",*pi);


 


所以总结如下:


const修饰在 pi 前,那么pi是个不可更改的值,永远指向一个地址,但可以通过*pi=xx来更改所指的变量的值。


const修饰在*pi前,那么不能出现*pi=xx这样的语句,pi可更改,pi所指向的变量也可以更改。


 


4.const类型指针与const类型变量


有三种情况。


情况一:int *pi指针指向const int i常量


const int a = 10;


int *pi;


pi = &a; //此种情况下据说VC会报错,因为pi指向a,那么就可以通过pi更改a的值,违背了代码初衷


pi = (int*) &a //强制转换,VC编译通过,但是仍不能*pi=xx来修改a的值


但是上面的代码在CodeBlocks下面可编译通过,也能修改a的值,不过一般最好不要这么写


 


情况二: const int *pi指针指向const int i1


const int a = 10;


const int *pi;


pi = &a; //编译通过,不过此时无法通过*pi或者a来更新变量的值,但pi可以重赋值为另一个变量地址


 


情况三:const int * const pi声明的指针


int i;


const int * const pi = &i; //此时pi不能更改,*pi亦不能更改


原创粉丝点击