变量、指针、参数、数组、内存分配的关系和陷阱

陷阱1:传入一个无指针的指针变量作为形参,你是无办法往里面塞地址或内容的

例子1


#include "stdlib.h"
#include "stdio.h"

void shit(char *p){
      printf("p之前指向的地址是:%d\n",p);
      p= (char*)malloc(sizeof(char));
      printf("p现在指向的地址是:%d\n",p);
}
main(){
      char *s;
      shit(s);
      printf("%d\n",s);
}


结果:

p之前指向的地址是:-858993460

p现在指向的地址是:4787976

-858993460



解释:

因为变量的本质其实在计算机里面并没有一个真正的变量名与知对应的,其实也都是地址,这样传入相当于一个根本不存在的地址传入到了子函数里面,子函数对它做任何操作其实都是无用功,并不会对主函数里面的s指向的虚无的位置有任何作用。Shit函数里面的p = (char*)malloc(sizeof(char));其实仅仅只是弄了个内存区域,把首地址给形参变量名对应起来,跟主函数的s毛关系都没有。

所以有些人弄了个虚无指针例如char *p,然后里面没地址的,塞进scanf("%s",p),想给它赋值是行不通一定错的,但编译器除了警告一下会由得你通过。


例子2

#include "stdlib.h"
#include "stdio.h"

void shit(char * p){
      p= (char*)malloc(6 * sizeof(char));
      scanf("%s",p);
}

main(){
      char s[4] = {'a','b','c','\0'};
      shit(s);
      printf("%s\n",s);
}

 

运行结果:

your  (输入)

abc


以为abc会被替换为your?错了,在形参p被重新分配内存区域地址开始,p保存的地址和s保存的首地址就已经不是同一个,那么p保存的地址指向的内容和s保存的首地址指向的内容当然就不会是同样的了,现在无论p输入什么都不会和s有关系



数组和指针、变量本是同根生

例子1


main(){
      char s[4] = {'a','b','c','\0'},*t;
      t = &s;
      printf("%s\n",s);
      t[0]= 'x';
      printf("%s\n",s);
}


运行结果:

abc

xbc

解释:

t看起来只是指针而不是数组,但是却可以当数组那样用,是因为做了t = &s;后,无论是数组变量s,还是指针变量t,实际上只要调整其指向的首地址相同,指向的内容也只是同一回事,当然操作也可以一样了。也侧面说明其实数组变量其实只是一种指向某个连续内存空间的一种指针。

 

例子2


main(){
      char *s = (char*)malloc(6 * sizeof(char));
      s[0]= 'a';
      s[1]= 'b';
      s[2]= 'c';
      s[3]= 'd';
      s[4]= 'e';
      s[5]= '\0';
      printf("%s\n",s);
}


运行结果:

abcde

 

 

这里等效于char  t[6] = {’a’,’b’,’c’,’d’,’e’},结合例子1,相信大家可以很充分地发现数组和指针之间的联系和等效关系了。


例子3


main(){
      char *head,*s;
      int i = 0;
      head= s = (char*)malloc(6 * sizeof(char));
      for(i=0;i<4;i++){
           *s= (char)'a' + i;
           s++;//因为char只有1字节,所以s++等效于s = s +sizeof(char); 
      }
      *s= '\0';
      printf("%s\n",head);
}

 


运行结果:

abcd


例子4

main(){
      char s[5] = {'a','b','c','d','\0'},*p;
      int i = 0;
      p= &s;
      for(i=0;i<4;i++){
           *p= (char)'w' + i;
           p++;//因为char只有1字节,所以s++等效于s = s +sizeof(char); 
      }
      printf("%s\n",s);
}


运行结果:

wxyz


解释:

这里做的证明是,因为数组不过只是一种指向连续内存区域首地址的一种变量,也正因为如此,这里做了一个等效于数组本质做的工作的一种指针,然后证明用普通变量的方法进行自加和赋值也是可行的。


陷进2:不小心改了指针变量的地址


main(){
    int a = 5,*p;
    p = &a;
    printf("p指向的地址:%d\n",p);
    printf("p指向的地址存的值:%d\n",*p);
    p = 543; //想改p的内容,却不小心忘记在前面加*(即*P),而是直接改了p指向的地址
    printf("p指向的地址:%d\n",p);
    printf("p指向的地址存的值:%d\n",*p);  //直接报错
}


运行结果:

p指向的地址:1638212

p指向的地址存的值:5

p指向的地址:543

(最后出错)


使用指针的时候,一定要注意操作规范,不然很容易摆乌龙,而且基本都可以编译通过,就是运行出错而已。 

 声明完指针之后,无论是给地址指向的空间赋值还是读取值,都要用   *指针变量名    来操作
而读取指针指向的地址(一个整数)时,直接用 指针变量名  即可


理解费解者可以这么理解:

指针变量存的是地址,可以理解为门牌号。普通变量存的是住在里面的人。








你可能感兴趣的:(C语言,理论基础,数据结构,指针,陷阱)