Record18—1级指针易错模型分析

目录

char *(字符串)做函数参数出错模型分析 

越界

不断修改指针变量的值

你向外面传递什么

优先级问题


 

char *(字符串)做函数参数出错模型分析 

看下面这段代码,实现将p指向的内存空间的内容复制到to中。

void copy_str21(char *from, char *to)
{
	if (*from != '\0')
	{
		printf("ddddd");
	}
	for (; *from!='\0'; from++, to++)
	{
		*to = *from;
	}
	*to = '\0';
}
//字符串逆序
int main()
{
	char *p = NULL;
	char to[100];
	copy_str21(p, to);

其中,典型错误段:

	if (*from != '\0')
	{
		printf("ddddd");
	}

这样判断是不行的,因为“*from”代表的是指针from指向的空间所存放的内容,而"from"本身是个指针变量,它可以是任意的值。在判断的时候,应该是判断指针变量而不是判断指针变量所指向的内存空间。我们这个的判断目的是为了判断传过来的是不是空指针,故正确的判断方式应该是:

	if (from == NULL)
	{
		printf("ddddd");
	}

在往深说一层,如果按原来错误的判断方式,为什么*from就不能是"\0"了呢?如果所定义的"char p[1024] = {0}",那这个p本身的所以内容都可以是”\0“,那凭什么能说指向人家的这块儿内容是空指针呢?所以,上述的那种方式肯定是错的。

 

越界

直接上例子:

char buf[3] = "abc";

这个是在语法级别的越界,"abc"作为字符串传入的时候,不是3个字节,而是,4个,"abc\0",所以buf只开3个单位,没考虑"\0"也会占一位。但这不会报错,C++编译器会自动的帮你检查,补充。

再举一个:

char *getKeyByValude(char **keyvaluebuf, char *keybuf)
{
      int i = 0;
      char *a = (char*)malloc(50);
      printf("%x", a);
      for(; **keyvaluebuf != "\0" ; i++)
      {
          *a++ = *(*keyvaluebuf)++;
      } 
      free(a);
}

这段代码用的是二级指针,但犯了一个关于越界的经典错误。当按顺序改变一级指针指向的内容时,就逐步改变指针本身内容逐个加1就行了,指针本身的内容也在一直改变,每次都发生变化;同理,当按顺序改变二级指针指向的内容时,就逐步改变对应的一级指针本身内容逐个加1就行了。一级指针本身的内容也在一直改变,每次都发生变化。那么,再返回到这个例子当中,"*a++"一直在变化,本来开辟的是,*a是一个在堆栈区开的内存空间,使用完之后,应该通过*a本身指向的这段内存空间的首地址,来进行析构,但"*a++"一直在变化,那最后*a的值,就不是指向*a所开辟的这段内存空间的首地址了,而是这段内存空间的最后一个地址了,当析构的时候,就会发生内存泄漏。

 

不断修改指针变量的值

void copy_str_err(char *from, char *to)
{
	for (; *from!='\0'; from++, to++)
	{
		*to = *from;
	}
	*to = '\0';
	printf("to:%s", to);
	printf("from:%s", from);
}

这个例子,传过来一个形参"*from",然后,将这个参数不断改变"from",然后,之后又用from,这种情况,最好,用一种辅助指针来做就好了。

 

你向外面传递什么

// char *str_cnct(x,y)     /*简化算法*/
// 	char *x,*y;
char *str_cnct(char *x, char* y)     /*简化算法*/
{
	char str3[80];
	char *z=str3; 	/*指针z指向数组str3*/ 
	while(*z++=*x++);
	z--;	               /*去掉串尾结束标志*/
	while(*z++=*y++);
	z=str3;		 /*将str3地址赋给指针变量z*/
	return(z);
}


Main ()
{
Char *p = str_cnct(“abcd”, “ddeee”);
If (p != NULL) {Free(p) ;p = NULL}//yezhizhen
}

其中,

	char str3[80];

是在被调函数当中分配的内存空间,当运行完之后,这块内存空间就消失了。向外啥也传递不了。

正确的写法,直接在堆栈区开辟空间存放内容,只要不擦,就一直有,如下:

while(*z++=*x++);
	z--;	               /*去掉串尾结束标志*/

char *str_cnct(char *x, char* y)     /*简化算法*/
{
	char * str3= (char *)malloc(80)
	char *z=str3; 	/*指针z指向数组str3*/ 
	while(*z++=*x++);
	z--;	               /*去掉串尾结束标志*/
	while(*z++=*y++);
	z=str3;		 /*将str3地址赋给指针变量z*/
	return(z);
}



Main ()
{
Char *p = str_cnct(“abcd”, “ddeee”);
If (p != NULL) {Free(p) ;p = NULL}//yezhizhen
}

简化的写法如下:

char *str_cnct(char *x, char* y)     /*简化算法*/
{
If (x == NULL)
{
Return NULL;
}
	char * str3= (char *)malloc(80)
	char *z=str3; 	/*指针z指向数组str3*/ 
	while(*z++=*x++);
	z--;	               /*去掉串尾结束标志*/
	while(*z++=*y++);
	z=str3;		 /*将str3地址赋给指针变量z*/ note:
	return(z);

}

Main ()
{
Char *p = str_cnct(“abcd”, “ddeee”);
If (p != NULL) {Free(p) ;p = NULL}//yezhizhen
}

 

优先级问题

//char *p = "abcd11111abcd2222abcdqqqqq"; //字符串中"abcd"出现的次数。
//要求你 自己写一个函数接口,并且写出测试用例。
//完成功能为:求出“abcd”字串出现的次数
//输入:
int getSubCount(char *str, char *substr, int *   mycount)
{
	int ret = 0;
	char *p = str;
	char *sub = substr;
	int count = 0;

	if (str==NULL || substr==NULL || mycount == NULL)
	{
		ret = -1;
		return ret;
	}

	//char *p = "abcd11111abcd2222abcdqqqqqabcd";
	//char *p2 = NULL;
	//p2 = p;
	do 
	{
		p = strstr(p, sub);
		if (p!= NULL)
		{
			count++;
			//++后缀操作符优先级高,所以先执行*p操作 然后地址++
			//(*mycount)++;
                        *mycount++;

			p = p + strlen(sub);
		}
		else
		{
			break;
		}  
	} while (*p != '\0');
	//printf("count:%d \n", count);

	//mycount是实参的地址 *(实参的地址)
	*mycount = count;
	return ret;
}

其中,关注这行代码:

			//++后缀操作符优先级高,所以先执行*p操作 然后地址++
			//(*mycount)++;
                        *mycount++;

注释掉的第二行是正确的,没注释的第三行会报错,这是为什么呢?因为"++"后缀的优先级高,当执行第三行的时候,先执行++操作,地址变量指向下一个,造成了地址变量和地址指向的内容错位,这个时候,就会出现地址跑偏的状况,原来的指向当前的地址,就指向了下一个地址了,那下一次再做++的时候,就错了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值