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