(三)C 语言之指针专题一
程序员文章站
2024-01-03 09:07:04
...
1.1 指针铁律1 指针也是一种类型
1.1.1 指针是变量
- 指针也是一种变量,占有内存空间,用来保存内存地址
- 测试指针变量占有内存空间大小 sizeof(char *);
printf("sizeof(char *)=%d\n",sizeof(char*)); //4 32位平台 ,//8 64位
printf("sizeof(int *)=%d\n",sizeof(int*)); //4 32位平台 ,//8 64位
1.1.2 *p操作
1.1.2.1 理论
- 在指针声明时,*号表示所声明的变量为指针
- 在指针使用时,*号表示 操作 指针所指向的内存空间中的值
- *p相当于通过地址(p变量的值)找到一块内存;然后操作内存
- *p放在等号的左边赋值(给内存赋值)
- *p放在等号的右边取值(从内存获取值)
1.1.2.2 代码
int main()
{
int a = 10;
char *p1 = 100; //分配4个字节的内存
char ****p2 = 100;
int *p3 = NULL;
p3 = &a;
*p3 = 20; //间接的修改a的值
//*就像一把钥匙 通过一个地址(&a),去修改a变量的标示的内存空间
{
int c = 0;
c = *p3; //c=20
//*p放在=号左边 写内存
//*p放=号的右边 读内存
printf("c:%d \n", c);
}
{
char *p4 = NULL;
p4 = (char *)malloc(100);
p4 = (char *)malloc(200); //0xcc11
//指针变量和它指向的内存块是两个不同的概念
//不断的给指针赋值,相当于不停的改变指针的指向(初学者一个误区,就是指针已经指向另外一个内存地址,他仍认为还指在原来的地址)
//p++ 只是改变了指针的指向,内存空间并没有改变
}
return 0;
}
1.1.3 指针变量和它指向的内存块是两个不同的概念
- 含义1 给p赋值p=0x1111; 只会改变指针变量值,不会改变所指的内容;p = p +1; //p++
- 含义2 给p赋值p=‘a’; 不会改变指针变量的值,只会改变所指的内存块的值
- 含义3 =左边p 表示 给内存赋值, =右边p 表示取值 含义不同!
- 含义4 =左边char *p
- 含义5 保证所指的内存块能修改
1.1.4
- 指针是一种数据类型,是指它指向的内存空间的数据类型
- 含义1:指针步长(p++),根据所致内存空间的数据类型来确定
- p++=(unsigned char )p+sizeof(a);
- 结论:指针的步长,根据所指内存空间类型来定。
注意: 建立指针指向谁,就把把谁的地址赋值给指针。图和代码和二为一。
不断的给指针变量赋值,就是不断的改变指针变量(和所指向内存空间没有任何关系)。
char *getStr()
{
char *tmp = NULL;
tmp = "abcdefgf";
return tmp;
}
int main()
{
char *p = getStr();
printf("p:%s \n", p);
*(p+2) = 'r'; //经常出现的错误 保证指针所指向的内存空间 可以被修改
return 0;
}
注意画出内存四区图
/*
int getABC1(char *p1); int getABC1(char* p1);
int getABC2(char ** p2); int getABC2(char * *p2); int getABC2(char **p2);
int getABC3(char ***p3);
int getABC4(char (*p4)[30]); int getABC4(char (*p4) [30]);
int getABC5(char p5[10][30]); int getABC5(char p5[10][30]);
//指针做函数参数 形参有多级指针的时候,
//站在编译器的角度 ,只需要分配4个字节的内存(32bit平台)
//当我们使用内存的时候,我们才关心指针所指向的内存 是一维的还是二维的
*/
1.1.6 野指针
野指针产生原因:
- 指针变量和它所指向的内存空间变量是两个不同的概念
- 释放了指针所指向的内存空间,但是指针变量本身没有重置成NULL;
避免方法 :定义指针的时候 初始化成nuLL。释放指针所指向的内存空间后,把指针重置成NULL。
int main()
{
char *p = NULL;
p = (char*)malloc(20);
strcpy(p,"zhangsan");
printf("p=%s\n",p);
if(p!= NULL)
{
free(p);
}
if(p!= NULL) //p释放了两次,就会报错
{
free(p);
}
return 0;
}
1.1.7 铁律1强化
int main()
{
char buf[64];
char * p1= NULL;
char * p2 = NULL;
p1 = &buf[0];
p1 = &buf[1];
p1 = &buf[2];
for(int i =0;i<64;i++) //不断的修改p1的值 相当于 不断改变指针的指向
{
p1= &buf[i];
}
p2 = (char*)malloc(100);
strcpy(p2,"zhangasdfasdf");
for(int i =0;i<10;i++)
{
p1= p2 +i;
printf("%c",*p1);
}
return 0;
}
1.2 间接赋值(*p)是指针存在的最大意义
1.2.1 理论
- 两码事:指针变量和它指向的内存块变量
- 指针指向某个变量,就是把某个变量地址赋给指针
- *p间接赋值成立条件:3个条件
- 2个变量(通常一个实参,一个形参)
- 建立关系,实参取地址赋给形参指针
- *p形参去间接修改实参的值
- 引申: 函数调用时,用n指针(形参)改变n-1指针(实参)的值。
- //改变0级指针(int iNum = 1)的值有2种方式
- //改变1级指针(eg char *p = 0x1111 )的值,有2种方式
- //改变2级指针的(eg char **pp1 = 0x1111 )的值,有2种方式
- //函数调用时,形参传给实参,用实参取地址,传给形参,在被调用函数里面用*p,来改变实参,把运算结果传出来。
- //指针作为函数参数的精髓。
1.2.2 案例
1.2.2.1 一级指针的技术推演
int getFileLen(int *p)
{
*p = 41; // p的值是a的地址 *a的地址间接修改a的值
//在被调用函数里面 通过形参 去 间接的修改 实参的值...
}
//形参的属性
int getFileLen2(int b)
{
b = 100;// p的值是a的地址 *a的地址间接修改a的值
}
//1级指针的技术推演
int main()
{
int a = 10; //条件1 定义了两个变量(实参 另外一个变量是形参p)
int *p = NULL;
//修改a的值
a = 20; //直接修改
p = &a; //条件2 建立关联
*p = 30; //p的值是a的地址 *就像一把钥匙 通过地址 找到一块内存空间 求间接的修改了a的值
printf("a: %d \n", a);
{
*p = 40; // p的值是a的地址 *a的地址间接修改a的值 //条件3 *p
printf("a: %d \n", a);
}
getFileLen(&a); //建立关联: 把实参取地址 传递给 形参
printf("getFileLen后 a: %d \n", a);
getFileLen2(a);
printf("getFileLen3后 a: %d \n", a);
return 0;
}
1.2.2.2 二级指针的技术推演
void getMem(char **p2)
{
*p2 = 400; //间接赋值 p2是p1的地址
}
void getMem2(char *p2)
{
p2 = 800; //间接赋值 p2是p1的地址
}
int main()
{
char *p1 = NULL;
char **p2 = NULL;
p1 = 0x11;
p2 = 0x22;
//直接修改p1的值
p1 = 0x111;
//间接修改p1的值
p2 = &p1;
*p2 = 100; //间接赋值 p2是p1的地址
printf("p1:%d \n", p1);
{
*p2 = 200; //间接赋值 p2是p1的地址
printf("p1:%d \n", p1);
}
getMem(&p1);
getMem2(p1);
printf("p1:%d \n", p1);
return 0;
}
1.2.2.3 间接赋值是指针存在的最大意义案例
int getMem(char ** str1 /*out*/,int * len1 /*out*/,char ** str2 /*out*/,int * len2 /*out*/)
{
char * tmp1 = NULL;
char * tmp2 = NULL;
tmp1 = (char*)malloc(sizeof(char) * 20);
tmp2 = (char*)malloc(sizeof(char) * 30);
strcpy(tmp1,"zhangsan");
strcpy(tmp2,"list");
*len1 = strlen(tmp1);
*len2 = strlen(tmp2);
*str1 = tmp1;
*str2 = tmp2;
}
int main()
{
char * str1 = NULL;
char * str2 = NULL;
int len1 = 0;
int len2 = 0;
getMem(&str1,&len1,&str2,&len2);
printf("strl =%s\n",str1);
printf("str2 = %s\n",str2);
printf("len1 =%d\n",len1);
printf("len2=%d\n",len2);
if(str1 != NULL)
{
free(str1);
str1 = NULL;
}
if(str2 != NULL){
free(str2);
str2 = NULL;
}
printf("zhangsan\n");
return 0;
}
参考一 : 狄泰软件课程
参考二 : 传智扫地僧老师课程
如有侵权:请联系邮箱 aaa@qq.com