C语言面试题分享(6)

注:以下都是找错题(即:找出程序中的错误或不合理的地方)
一、

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

猜你喜欢

转载自blog.csdn.net/weixin_44788542/article/details/113887310