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

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

}

NULL 地址写入数据

不可预料的地址写入数据

不断改变指针的指向:

#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  请按任意键继续. . .

 */

一级指针 内存模型的建立

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

	//见图
}

/*
 编译运行:

 */

字符串做函数参数

#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种方法

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

/*
 编译运行:

 */

练习题:

第一题,我的答案:

#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) 是指针存在的最大意义

时间: 2024-10-05 05:41:35

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

指针间接赋值

#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h> /*间接赋值成立的三个条件: 条件一://定义一个实参 //定义一个形参 条件二://建立关联:把实参取地址传给形参 条件三://形参间接去修改实参的值 */ /* 用n级指针形参,去间接的修改n-1级指针(实参)的值. */ /*间接赋值的场景 //1 2 3 这3个条件 写在有一个函数 //12 写

绝不要进行两层间接非const指针赋值给const指针

#include <stdio.h> #include <stdlib.h> int main(void) { int *p1; int * *pp1; const int * *pp2; const int n = 13; printf("起初const int n = %d\n", n); pp1 = &p1; pp2 = pp1; *pp2 = &n; /*  间接的使p1=&n  */ **pp1 = 10; printf(&qu

间接赋值从1级指针到2级指针

void getMem(char **p2){ *p2 = 400; //间接赋值,p2是p1的地址} int main(){ char *p1 =NULL; char **p2 =NULL; p1 = 0x111; //间接改变p1的值 p2 = &p1; *p2 = 100; //间接赋值,p2是p1的地址 printf("p1:%d\n", p1); { *p2 = 200; //间接赋值,p2是p1的地址 printf("p1:%d\n", p1);

c语言常量指针赋值给变量指针导致警告

常量指针定义:常量是形容词,指针是名词,以指针为中心的一个偏正结构短语.这样看,常量指针本质是指针,常量修饰它,表示这个指针乃是一个指向常量的指针.指针指向的对象是常量,那么这个对象不能被更改.常量指针的使用要注意,指针指向的对象不能通过这个指针来修改,可是仍然可以通过原来的声明修改,也就是说常量指针可以被赋值为变量的地址,之所以叫做常量指针,是限制了通过这个指针修改变量的值. 在C/C++中,常量指针是这样声明的: 1)const int *p; 2)int const *p; 例子: int

C语言中,为什么字符串可以赋值给字符指针变量

转载于:http://www.cnblogs.com/KingOfFreedom/archive/2012/12/07/2807223.html 本文是通过几篇转帖的文章整理而成的,内容稍有修改: 一. char *p,a='5';p=&a;                     //显然是正确的,p="abcd";              //但为什么也可以这样赋值?? 问:一直理解不了为什么可以将字串常量赋值给字符指针变量,请各位指点! 答: 双引号做了3件事:  1.

变量的直接赋值和间接赋值

直接赋值:直接赋予参数值的方式称为直接赋值. 间接赋值:由交互的方式赋值为间接赋值.(a就是一个变量) 原文地址:https://www.cnblogs.com/zteng/p/10303728.html

间接赋值从0级指针到1级指针

#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h> int getFileLen(int b){ b = 100; return b;}int getFileLen2(int *p){ *p = 44; return *p;} //一级指针的推演int main(){ int a; int *p =NULL; //修改a的值 a = 20; //直接修改

字符串赋值给字符指针变量

char *p,a='5'; p=&a;                     //显然是正确的,p="abcd";              //但为什么也可以这样赋值?? 双引号做了3件事: 1.申请了空间(在常量区),存放了字符串 2. 在字符串尾加上了'/0'    3.返回地址 这里就是 返回的地址  赋值给了  p                       char *p = "hello"; 把p换成数组,然后再赋值就不行 字符串常量&qu

指针锱铢---指针的声明赋值,野指针的灾难性后果

#include <stdio.h>int main(){  int a = 10; int *p; p = &a; printf("这就是指针p指向的地址里存的值%d ,说起来容易,用起来准糊涂\r\n", *p); //改了指针指向的地址的内容 *p = 8888; printf("这样一来,a的值就变成了%d\r\n",a); //int *wenwa=NULL;//野指针,通常不允许给野指针赋值,万一指向的是操作系统核心模块地址,放开肆意