注:以下都是找错题(即:找出程序中的错误或不合理的地方)
一、
void test1()
{
char string[10];
char* str1 = "0123456789";
strcpy(string, str1);
}
解答:字符串str1有11个字节(包括末尾的结束符’\0’),而数组string只有10个字节,故而使用strcpy函数将str1复制到string中会导致数组string越界一个字节,可能导致系统崩溃。
题外:
使用如下例程探究一下strcpy函数复制字符串时是否会把’\0’也一并复制过去。
int main(void)
{
unsigned char str1[10] = {
0};
unsigned char* str2="123";
int i=0;
memset(str1,0xff,sizeof(str1));
for(i=0;i<10;i++)
{
printf("%X ",str1[i]);
}
printf("\r\n");
strcpy(str1,str2);
for(i=0;i<10;i++)
{
printf("%X ",str1[i]);
}
printf("\r\n");
}
结果:
可见strcpy函数复制字符串时会把’\0’也一并复制过去。
上面这个测试记录一个小问题
一开始unsigned char str1[10] = {0};用的是char型的,导致%X输出来每个元素是0xFFFFFFFF,与设想的0xFF不符,究其原因是%x要求的是无符号整形变量,而如果传入的是char型,这里有一个整数提升的问题。char作为有符号数,提升到无符号整数,由于char的值为0xFF,那么提升时,前面的填充位为1。所以提升后其值为0xFFFFFFFF
解决办法:
把char类型强制转换为uint8_t(即unsigned char),使用uint8_t时,是无符号提升,前面的填充为0,所以提升后的值为0xFF
二、
void test2()
{
char string[10], str1[10];
int i;
for(i=0; i<10; i++)
{
str1= 'a';
}
strcpy(string, str1);
}
解答:str1[10]是局部变量,没有初始化可能元素都是随机数,因此str1[]里可能没有没有结束符’\0’,strcpy函数是把含有’\0’结束符的字符串source(包含’\0’)复制到另一个地址空间destin。故而使用strcpy复制时很可能导致数组越界引起系统崩溃。
三、
void test3(char* str1)
{
char string[10];
if(strlen(str1) <= 10 )
{
strcpy(string, str1);
}
}
解答:应修改为if (strlen(str1) < 10),因为strlen的结果未统计最后的结束符’\0’,如果str1恰好是11个字节的字符串包含最后的’\0’,使用strcpy时会导致string写入越界。
四、
void GetMemory(char *p)
{
p = (char *)malloc( 100 );
}
void Test( void )
{
char *str = NULL;
GetMemory(str);
strcpy(str,"hello world");
printf(str);
}
解答:C语言中的函数参数为传值参数,在函数内对形参的修改并不能改变对应实参的值。故而调用GetMemory后,str的值没有改变,仍为NULL。这里完成功能要用二级指针。
另外一个错误,没有释放内存。
正确的应改为:
void GetMemory(char **p)
{
*p=(char *)malloc(100);
}
void Test( void )
{
char *str = NULL;
GetMemory(&str);
strcpy(str,"hello world");
printf(str);
free(str);
str=NULL;
}
评析:
(1)目的:通过调用子函数,为主函数指针分配一块内存空间;
在调用GetMemory时,实参值为&str,即指针str的地址;GetMemory执行时,分配临时变量p=&str; p=(char)malloc(100)操作等同于:str=(char*)malloc(100);即通过调用子函数,为主函数指针分配一块内存空间。
(2)注意:如果malloc函数被调用,则后续函数中一定需要有free将对应的内存释放,否则可能导致内存泄露;当free§后,需要让p=NULL,否则指针p会成为野指针!
五、
char *GetMemory( void )
{
char p[] = "hello world";
return p;
}
void Test( void )
{
char *str = NULL;
str = GetMemory();
printf(str);
}
解答:GetMemory中,p数组为局部变量,在函数返回后,该数组空间被释放。故而str指向被释放的地址空间,可能打印乱码。实测如下:
六、
void GetMemory( char **p, int num )
{
*p = (char *)malloc(num);
}
void Test( void )
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
解答:试题6避免了试题4的问题,但在GetMemory内,未对p为NULL情况的判断。当p不为NULL时,在printf后,也未对malloc的空间进行free。
七、
void Test( void )
{
char *str = (char *)malloc( 100 );
strcpy(str, "hello" );
free(str);
... //省略的其它语句
}
解答:未对str为NULL的情况的判断,在free(str)后,str未设置为NULL,可能变成一个野指针(后面对str的操作可能会导致踩内存)。
八、
swap(int* p1,int* p2)
{
int *p;
*p = *p1;
*p1 = *p2;
*p2 = *p;
}
解答:上述函数功能,p1和p2指向的int数进行值互换
在swap函数中,p是个野指针,*p操作将导致程序运行的崩溃。故而,程序应改为:
swap(int* p1,int* p2)
{
int p;
p = *p1;
*p1 = *p2;
*p2 = p;
}