欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

(三)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;
}

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

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;
}

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

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;
}

(三)C 语言之指针专题一
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;
}

(三)C 语言之指针专题一
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

相关标签: C语言

上一篇:

下一篇: