(三)C 语言之指针专题一

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 理论

  1. 两码事:指针变量和它指向的内存块变量
  2. 指针指向某个变量,就是把某个变量地址赋给指针
  3. *p间接赋值成立条件:3个条件
    • 2个变量(通常一个实参,一个形参)
    • 建立关系,实参取地址赋给形参指针
    • *p形参去间接修改实参的值
  4. 引申: 函数调用时,用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;

}

参考一 : 狄泰软件课程
参考二 : 传智扫地僧老师课程
如有侵权:请联系邮箱 1986005934@qq.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值