温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C 提高2 间接赋值(*p) 是指针存在的最大意义

发布时间:2020-06-12 09:34:53 来源:网络 阅读:802 作者:990487026 栏目:开发技术


1野指针强化:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 野指针产生的原因
//指针变量和它指向的内存空间变量是两个不同的概念
//释放了指针所指向的内存空间,但是指针变量本省没有重置为NULL
//造成释放的时候,通过if(p1 != NUll)
//避免方法:
// 1)定义指针的时候,初始化成NULL
// 2)释放指针所指向的内存空间,把指针重置成NULL

int main()
{
	char *p1 = NULL;
	p1 = (char *)malloc(100);
	if (p1 == NULL)
	{
		printf("没有分配到堆空间 \n");
		return 0;
	}
	strcpy(p1, "1234567890");
	printf("%s \n", p1);

	if (p1 != NULL)
	{
		free(p1);
		//p1 = NULL;//如果没有这个步骤,下面的再次释放就导致程序出错(VS2013)
	}
	if (p1 != NULL)
	{
		free(p1);
	}

}

C 提高2  间接赋值(*p) 是指针存在的最大意义





NULL 地址写入数据

不可预料的地址写入数据

不断改变指针的指向:

C 提高2  间接赋值(*p) 是指针存在的最大意义

C 提高2  间接赋值(*p) 是指针存在的最大意义


C 提高2  间接赋值(*p) 是指针存在的最大意义


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	char  buf[20] = { 'a', '1', 'b', '2', 'c', '3', 'd', '4', 'e', '5' };
	char *p1 = NULL;
	char *p2 = NULL;

	p1 = &buf[0];
	p1 = &buf[1];
	p1 = &buf[2];

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		p1 = &buf[i];
		printf("%c ", *p1);
	}

	p2 = (char *)malloc(20);
	strcpy(p2,"1234567890");
	for (i = 0; i < 10; i++)//不断的修改指针的值,相当于不断改变指针的指向
	{
		p1 = p2+i;//注意p2的步长是char
		printf("%c ",*p1);
	}
	free(p2);
	system("pause");

}

编译运行:
C:\Users\chunli>gcc main.c & a
a 1 b 2 c 3 d 4 e 5 1 2 3 4 5 6 7 8 9 0 请按任意键继续. . .



字面量:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	//结论:字面量不能取地址,没有放在栈区,也没有放在堆区,因为没法取其地址
	//我觉得放在代码区
	int i = 0;				 //字面量 0   0不能取地址
	for (i = 0; i < 10; i++) //字面量 10  10不能取地址
	{
		printf("Hello World! \n");
	}


}
便于运行:
C:\Users\chunli>gcc main.c & a
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!


从0级指针到1级指针:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int fun1()
{
	int a = 20;
	return a;
}

int fun2(int a)
{
	a = 30;
}

int fun3(int *a)
{
	*a = 40;
}

int main()
{
	int a = 10;
	int *p = NULL;
	p = &a;
	printf("%d \n",*p);

	fun1();
	printf("%d \n", *p);

	fun2(a);			//只是把a的数值传过来,用来初始化函数的值,除此之外,函数内与a没有任何关系了
	printf("%d \n", *p);

	fun3(&a);			//只有把a的地址传过来,才能对a进行修改
	printf("%d \n", *p);

	system("pause");

}
 /*
编译运行:
10
10
10
40
请按任意键继续. . .
 */


 从1级指针到2级指针:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>

void fun1(char **p2)	//只有这种方法才能修改一级指针的数值
{
	*p2 = 0xff;	//间接修改一级指针的值,而不是修改一级指针指向的内存块
}

void fun2(char *p2)		//这种方法永远也不可能修改传过来的一级指针的数值
{	
	//char *p2			就相当于是在这里定义了一个p2指针变量,和外界的一级指针没有任何关系
	p2 = 0xf;	
}

int main()
{
	char *p1 = NULL;
	char *p2 = NULL;

	//直接修改p1的值
	p1 = 0x22;
	p2 = 0x55;

	//间接是修改p1的值
	p2 = &p1;				 //把p1的地址装入p2
	*p2 = 100;				 //把变量p1的值修改为100
	printf("%d \n",p1);		//把p1的数值打印出来
	fun1(&p1);				//间接修改一级指针的值,而不是修改一级指针指向的内存块
	printf("%d \n", p1);	//把p1的数值打印出来

	fun2(p1);
	printf("%d \n", p1);	//把p1的数值打印出来

	system("pause");

}
 /*
 编译运行:
 100
 255
 255
 请按任意键继续. . .
 */




【重要概念】


间接赋值(*p) 是指针存在的最大意义

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void fun1(char **myp1, int *mylen1, char **myp2, int *mylen2)
{ 
	int ret = 0;
	char *tmp1 = NULL;
	char *tmp2 = NULL;

	//间接赋值
	tmp1 = (char *)malloc(100);
	strcpy(tmp1, "1234567890");
	*mylen1 = strlen(tmp1);// 1级指针
	*myp1 = tmp1;		   //2级指针

	tmp2 = (char *)malloc(200);
	strcpy(tmp2, "abcdefg");
	*mylen2 = strlen(tmp2);// 1级指针
	*myp2 = tmp2;		   //2级指针
}
int main()
{
	/*
	原来p1的值是NULL,通过函数调用,p1指向了一块内存区域
	*/
	char	*p1 = NULL;
	char	*p2 = NULL;
	int		len1 = 0;
	int		len2 = 0l;
	int		ret = 0;
	fun1(&p1, &len1, &p2, &len2);
	if (ret != 0)
	{
		printf("error :%d \n", ret);
	}
	printf("%s \n", p1);
	printf("%s \n", p2);

	if (p1 != NULL)
	{
		free(p1);
		p1 = NULL;
	}

	if (p2 != NULL)
	{
		free(p2);
		p2 = NULL;
	}


	system("pause");
	return ret;

}
 /*
 编译运行:

 1234567890
 abcdefg
 请按任意键继续. . .




 */




间接赋值的成立条件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void fun1(int *p)
{
	*p = 50;
}
int main()
{
	//条件1,定义了2个变量
	int a = 0;
	int *p = NULL;

	//条件2,建立关联
	p = &a;

	//条件3,*p间接修改
	*p = 10;

	printf("%d \n",a);

	//一级指针与函数
	fun1(&a); //把实参的地址传给形参,建立关联
	printf("%d \n", a);

	system("pause");
	return 0;
}



 /*
 编译运行:
 10
 请按任意键继续. . .
 */


//间接赋值的应用场景

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
间接赋值成立的三个条件:
条件1:定义变量(实参),定义变量(形参)
条件2:建立关联
条件3:形参去间接的修改了实参的值
*/

//间接赋值的应用场景

// 条件1 2 3 写在一个函数中
int main()
{
	char from[100] = { 0 };
	char   to[100] = { 0 };
	char *p1 = from;
	char *p2 = to;

	strcpy(from,"112233445566");
	while (*p1 != '\0')
	{
		*p2++ = *p1++;
	}
	printf("%s \n",to);
	system("pause");
	return 0;
}



 /*
 编译运行:
 112233445566
 请按任意键继续. . .

 */


字符串与一级指针  专题 ---  //字符数组的初始化

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//字符串与一级指针  专题 ---  //字符数组的初始化

// 1 C语言中的字符串是以数字0结尾的
// 2 在C语言中没有字符串类型,通过字符数组来模拟字符串
// 3 字符串的内存分配可以在堆上 栈上 常量区 


int main()
{
	
	char buf1[100] = { 'a', 'b', 'c', 'd' };//除前面4个外,其他全是0
	printf("%d \n",buf1[99]);
	//char buf2[2] =   { 'a', 'b', 'c', 'd' };//大于初始化的内存个数,编译器报错
	char buf3[] =    { 'a', 'b', 'c', 'd' };//这不是以0结尾的字符串
	char buf4[] = "abcd";		//数组的大小是5,字符长度是4
	int size = sizeof(buf4);
	int len = strlen(buf4);
	printf("size=%d,  len=%d \n",size,len);


	system("pause");
	return 0;
}



 /*
 编译运行:

 0
 size=5,  len=4
 请按任意键继续. . .


 */




字符串与一级指针  专题 -- 用数组和指针操作字符串

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
//字符串与一级指针  专题 -- 用数组和指针操作字符串
//普通指针与数组变量名字的区别
int main()
{
	int i = 0;
	char *p1 = NULL;
	char buf1[128] = "abcdefg";
	for (i = 0; i < strlen(buf1);i++)
	{
		printf("%c ",buf1[i]);
	}

	//用指针操作字符串
	p1 = buf1;//buf代表数组元素的地址,这句话是错误的。应该说,buf代表数组首元素的地址
	for (i = 0; i < strlen(buf1); i++)
	{
		printf("%c  ", *(p1 + i)); //效果一样
		printf("%c  ", *(buf1 + i)); //效果一样 相当于buf1[i]
		//[] 到* 的推导过程
		//buf1[i] => buf1[0+i] => *(buf+i)  ,buf代表数组首元素的地址
		//其实[] 与 * 操作数组,没有多大的区别,只是中括号便于人们的阅读
	}

	//不允许的操作
    //buf1 = buf1 + 1;     左操作数必须为左值	  


	system("pause");
	return 0;
}
// 中括号[]的本质:和*是一样,只不过是符合程序员的阅读习惯
// buf是一个指针,只读的常量,buf是一个常量指针。
//为什么这么做?
//buf是一个常量指针,析构内存的时候,保证buf空间完整释放

 /*
 编译运行:
a b c d e f g a  a  b  b  c  c  d  d  e  e  f  f  g  g  请按任意键继续. . .

 */



一级指针 内存模型的建立

C 提高2  间接赋值(*p) 是指针存在的最大意义

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
//一级指针 内存模型的建立

int main()
{
	char buf1[20] = "aaa";
	char buf2[]   = "bbbb";
	char *p1 = "11111111111111";
	char *p2 = malloc(100);
	strcpy(p2,"333333");


	system("pause");
	return 0;

	//见图
}

/*
 编译运行:

 */

C 提高2  间接赋值(*p) 是指针存在的最大意义



字符串做函数参数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//字符串做函数参数

int main()
{
	char a[] = "i am a student";
	char b[64];
	int i = 0;
	for (i = 0; *(a + i) != '\0'; i++)
	{
		*(b + i) = *(a + i); //'\0' 并不会存入
	}
	b[i] = '\0'; //'\0' 并不会存入
	printf("%s \n",b);

	system("pause");
	return 0;
}

/*
 编译运行:

 i am a student
 请按任意键继续. . .


 */



字符串拷贝,3种方法

C 提高2  间接赋值(*p) 是指针存在的最大意义

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//字符串拷贝,3种方法

void copy_str1(char *from, char *to)
{
	while (*from != '\0')	//当遇到0就跳出来了
	{
		//指针的指向不断变化,小心啊
		// ++ 优先级高
		*to++ = *from++; //'\0' 并不会存入
		//相当于先 *to = *from, 在to++  from++
	}
	*to = '\0';
	return;
}


void copy_str2(char *from, char *to) //优化一下
{
	while ((*to = *from) != '\0')	//先把值赋过去,再判断
	{
		*to++;
		*from++; 
	}
}

//经典程序之一  字符串拷贝
void copy_str(char *from, char *to) //再优化一下
{
	while (*to++ = *from++);	//先把值赋过去,再判断
}


int main()
{
	char *from = "Hello";
	char buf[100] = {0};

	copy_str(from,buf);
	printf("%s \n",buf);
	system("pause");
	return 0;
}

/*
 编译运行:

 i am a student
 请按任意键继续. . .


 */



经典程序之一  字符串拷贝

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//字符串拷贝,3种方法

//经典程序之一  字符串拷贝
//不要轻易改变形参的值
int copy_str(char *from, char *to) //再优化一下
{
	char * tmp_to = to; //引进一个辅助
	if (from == NULL  || to == NULL) return -1;
	while (*to++ = *from++);	//先把值赋过去,再判断
	//不能出现 printf("%s \n",to)这样的语句,因为to已经改变了
	printf("%s \n",tmp_to);
	return 0;
}


int main()
{
	int ret = 0;
	char *from = "Hello";
	//char *buf = NULL;
	char buf[20] ;


	ret = copy_str(from,buf);
	if (ret != 0)
	{
		printf("fun copy_str error %d  \n", ret);
	}

	printf("%s \n",buf);
	system("pause");
	return ret;
}

/*
 编译运行:

 i am a student
 请按任意键继续. . .


 */


项目开发字符串模型  do while 模型

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//项目开发字符串模型  do while 模型


int main()
{
	int count = 0;
	char *p = "11abcd123abcd234abcd23abcd2345abcd";
	do
	{
		p = strstr(p, "abcd");
		if (p != NULL)
		{
			count++;
			p = p + strlen("abcd");
		}
		else
		{
			break;
		}
	} while (*p != '\0');




	printf("%d \n" ,count);

	system("pause");
	return 0;
}

/*
 编译运行:

 */




项目开发字符串模型  while 模型

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
//项目开发字符串模型  while 模型

int main()
{
	int count = 0;
	char *p = "11abcd123abcd234abcd23abcd2345abcd";
	while (p=strstr(p,"abcd"))
	{
			count++;
			p = p + strlen("abcd");
			if (*p == '\0')
			{
				break;
			}
	} 




	printf("%d \n" ,count);

	system("pause");
	return 0;
}

/*
 编译运行:

 */



项目开发字符串模型  while 模型  --  API封装

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
//项目开发字符串模型  while 模型  --  API封装


int getCount(char *String/*in*/, char *sub/*i*/, int *count/* out*/)
{
	int tmp_count = 0;
	int ret = 0;
	char *p = String;

	if (String == NULL || sub == NULL)
	{
		ret = -1;
		printf("fun getCount  error String == NULL || sub == NULL %d \n ",ret);
		return ret;
	}
	while (p = strstr(p, sub))
	{
		tmp_count++;
		p = p + strlen(sub);
		if (*p == '\0')
		{
			break;
		}
	}
	*count = tmp_count;
	return 0;
}

int main()
{
	int ret = 0;
	int count = 0;
	char *p1 = "11abcd123abcd234abcd23abcd2345abcd";
	char *p2 = "abcd";
	ret = getCount(p1,p2,&count);
	if (ret != 0)
	{
		printf("fun fetCount error %d \n",ret);
	}



	printf("%d \n" ,count);

	system("pause");
	return ret;
}

/*
 编译运行:

 */


练习题:

C 提高2  间接赋值(*p) 是指针存在的最大意义

C 提高2  间接赋值(*p) 是指针存在的最大意义


第一题,我的答案:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int str_del(const char *str1/*in*/, char * str2/*out*/)
{
	int ret = 0;
	if (str1 == NULL || str2 == NULL)
	{
		ret = -1;
		printf("fun str_del  str1 == NULL || str2 == NULL  error: %d \n",ret);
		return ret;
	}

	char *p = str1;
	while (*p == ' ')
	{
		p++;//跳出空格
	}
	strcpy(str2, p);//从第一个非空格开始,写入原字符串

	int len = strlen(str2);
	if (str2[len-1] == ' ')//如果最后一位有空格
	{
		p = str2+len-1;//找到最后一个空格的位置
		while (*p == ' ')
		{
			*p = 0;
			p--;
		}
	}
	return ret;
}

int main()
{
	int ret = 0;
	char *str1 ="     abc 123   ";
	char str2[128];

	ret = str_del(str1,str2);
	if (ret != 0)
	{
		printf("error in fun str_del code:%d\n",ret);
		return ret;
	}
	printf("%s", str2);
	system("pause");
	return ret;
}

/*
 编译运行:
 abc 123请按任意键继续. . .
 */



第二题,我的答案:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int getstr(const char *str1/*in*/, char * str2/*out*/, char * str3/*out*/)
{
	int ret = 0;
	if (str1 == NULL || str2 == NULL || str3 == NULL)
	{
		ret = -1;
		printf("fun str_del  str1 == NULL || str2 == NULL || str3 == NULL  error: %d \n",ret);
		return ret;
	}

	char *p1 = str1;
	char *p2 = str2;
	char *p3 = str3;
	int i = 0;
	while (*p1 != '\0')
	{
		if (i % 2)
			*p2++ = *p1;
		else
			*p3++ = *p1;
		i++;
		p1++;
	}
	return ret;
}

int main()
{
	int ret = 0;
	char *string ="1a2b3c4da1b2c3d4";
	char str1[128] = { 0 };
	char str2[128] = { 0 };

	ret = getstr(string,str1,str2);
	if (ret != 0)
	{
		printf("error in fun str_del code:%d\n",ret);
		return ret;
	}
	printf("str1=%s\n", str1);
	printf("str2=%s\n", str2);


	system("pause");
	return ret;
}

/*
 编译运行:
 str1=abcd1234
 str2=1234abcd
 请按任意键继续. . .

 */



指针经典话语:

1,指针指向谁,就把谁的地址赋给指针;

2,指针变量 和 它指向的内存空间变量是两个不同的概念

3,理解指针的关键是内存,没有内存哪里来的指针


变量的本质是一个固定大小的数据块,变量名就是数据块的编号


内存的使用范围:

main函数可以在栈分配内存/堆分配内存/全局分配内存,可以给子函数使用

子函数在栈分配的内存不能给主函数使用,但是堆内存与全局变量是可以给main使用


编译器会为每个程序分配一个内存4区,主函数与子函数公用这个内存4区


建立正确程序运行内存布局图是学好C的关键!


 


指针铁律1:指针是一种数据类型

1)指针也是一种变量,占有内存空间,用来保存内存地址

2)*p 操作内存;

3)*就像一把钥匙,通过一个地址(&a),去修改a变量的标示的内存空间

4)不断的给指针赋值,相当于不停的改变指针的指向。

5) 指针是一种数据类型,是指它指向内存空间的数据类型

指针铁律1:间接赋值(*p) 是指针存在的最大意义





向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI