C++面试必知必会(3)-程序改错

1 对下列程序改错

#include<stdio.h>
int main() {
	char *src="hello,world";
	char *dest=NULL;
	int len=strlen(src);
	dest=(char *)malloc(len);
	char *d=dest;
	char *s=src[len];
	while(len--!=0)
		d++=s--;
		printf("%s",dest);
		return 0;
}

改错之后版本:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
	char *src="hello,world";
	char *dest=NULL;
	int len=strlen(src);
	dest=(char *)malloc(len);
	char *d=dest;
	char *s=&src[len-1];
	while(len--!=0)
		*d++=*s--;		
		*d=0;
		printf("%s",dest);
		free(dest);
		return 0;
}

标准答案:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
	char *src="hello,world";
	int len=strlen(src);
	char *dest=(char *)malloc((len+1)*sizeof(char));
	char *d=dest;
	char *s=&src[len-1];//指向最后一个字符
	while(len--!=0)
		*d++=*s--;		
		*d=0;//尾部要加\0
		printf("%s",dest);
		free(dest);//使用完以后,应当释放空间,以免造成空间泄露
		return 0;
}



2 分析下列程序

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void getmemory(char *p) {
	p=(char *)malloc(100);
	strcpy(p,"hello world");
}
int main() {
	char *src=NULL;
	getmemory(src);
	printf("%s\n",src);
	free(src);
	return 0;
}

造成程序崩溃,具体如下:

(1)getmemory中的malloc不能返回动态内存;

(2)free()对src操作很危险。


3 分析下列程序

void test1() {
	char string[10];
	char *str1="0123456789";
	strcpy(string,str1);
}
str1需要11个字节才能存放下(包括末尾的‘\0’),而string只有10个字节的空间,strcpy会导致数组越界。


4 分析下列程序:

void test2() {
	char string[10],str1[10];
	int i;
	for(int i=0;i<10;i++) {
		str1[i]='a';
	}
	strcpy(string,str1);
}
考察对数组越界把握。

分析:字符数组不能在数组内结束、strcpy(string,str1)调用使得从str1内存拷贝到string内存拷贝的字节数具有不确定性、在此基础上指出strcpy工作方式。

1对字符数组赋值后,使用库函数strcpy进行拷贝操作,strcpy会从源地址一直往后拷贝,直到遇到'\0'为止。所以拷贝的长度是不定的。如果一直没有遇到'\0'导致越界访问非法内存,程序就崩了

2 数组越界访问


修改后代码:


void test2()
{
    char string[10], str1[10];
    int i;
    for(i=0; i<9; i++)
    {
        str1[i]  = 'a';
    }
    str1[9] = '\0';
    strcpy( string, str1 );
}


5 分析下列程序

void test3(char *str1) {
	char string[10];	
	if(strlen(str1)<=10) {
		strcpy(string,str1);
	}	
}

将strlen(str1)<=10 改成strlen(str1)<10


考察strcpy库函数的工作方式,编写一个标准strcpy函数。

void strcpy(char *strDest, char *strSrc) {
	while((*strDest++ ==* strSrc++) != '\0');
}

void strcpy(char *strDest,const char *strSrc) {
	while((*strDest++ ==* strSrc++) != '\0');
}

void strcpy(char *strDest,const char *strSrc) {
	assert((strDest!=NULL)&& (strSrc!=NULL));
	while((*strDest++ ==* strSrc++) != '\0');
}

void strcpy(char *strDest,const char *strSrc) {
	assert((strDest!=NULL)&& (strSrc!=NULL));
	char *address=strDest;
	while((*strDest++ ==* strSrc++) != '\0');
	return address;
}

上述4种代码形式,越是后面的,质量越高。


试写一个strlen函数

int strlen(const char *str) {
	assert(str!=NULL);//断言字符串地址非0
	int len;
	while((*str++)!='\0') {
		len++;
	} 
	return len;
}


6  分析下述代码

void GetMemory(char *p) {
	p=(char *)malloc(100);
}
void test() {
	char *str=NULL;
	GetMemory(str);
	strcpy(str,"hello world");
	printf(str);
}
传入GetMemory(char *p)函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值去执行完。


7 分析下述代码

void GetMemory(void) {
	char p[]="hello world";
	return p;
}
void test() {
	char *str=NULL;
	str=GetMemory();
	printf(str);
}
这段代码的p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。



8 分析下述代码

void GetMemory(char **p,int num) {
	*p=(char *)malloc(num);//这段代码后面未进行内存申明成功的判断
}
void test() {
	char *str=NULL;
	GetMemory(&str,100);
	strcpy(str,"hello");
	printf(str);
}
传入GetMemory的参数为字符串指针的指针,但是在GetMemory中执行申请内存及赋值语句。

*p=(char *)malloc(num);后未判断内存是否申请成功,应加上:

if(*p == NULL) {

....//进行申请内存失败处理

}


9 分析下述代码

void Test(void) {
	char *str=(char *)malloc(100);//这段代码后面未进行内存申明成功的判断
	strcpy(str,"hello");
	free(str);//在free之后未置str为空,导致可能变成一个野指针
	//省略的其他语句 
}
char *str=NULL;

GetMemory(str);

这段代码后的str仍然为NULL。

10 以下代码有什么问题

int main() {
	char a;
	char *str=&a;
	strcpy(str,"hello");
	printf(str);
	return 0;
}
分析:没有为str分配内存空间,将会发生异常。

问题出现在将一个字符串复制进一个字符变量指针所指地址,虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。


11 分析下列程序

#define MAX 255
int main() {
	unsigned char A[MAX],i;//i被定义为unsigned char
	for(i=0;i<=MAX;i++)
		A[i]=i;
}
分析: 会造成死循环和数组越界访问(C/C++不进行数组越界检查)
MAX=255表示:

(1)数组A的下标范围为0~MAX-1

(2)当i循环到255时,循环内执行

本题中代码A[255]=255;这一句本没有问题,但是返回for(i=0;i<=MAX;i++)语句时,由于unsigned char的取值范围在0~255,i++以后i又为0 了,所以导致无限循环下去


12 改正下列程序错误

#include<stdio.h>
int main() {
	int **p;
	int arr[100];
	p=&arr;
	return 0;
}
指针类型不同。

int **p;//二级指针

&arr;//得到是指向第一维为100的数组的指针

将上述程序修改为如下:

#include<stdio.h>
int main() {
	int **p;
	int *q;
	int arr[100];
	q=arr;
	p=&q;
	return 0;
}

13  考察sizeof用法

void UpperCase(char str[]) {
	for(size_t i=0;i<sizeof(str)/sizeof(str[0]);++i)
		if('a'<=str[i] && str[i]<='z')
			str[i]-=('a'-'A');
}
char str[]="aBcDe";
cout<<"str字符长度为:"<<sizeof(str)/sizeof(str[0])<<endl;
UpperCase(str);
cout<<str<<endl;

分析:函数内的sizeof有问题,sizeof用于数组,只能测出静态数组大小,而无法检测动态分配的或外部数组大小。函数外的str是一个静态定义的数组,因此其大小为6,函数内的str实际只是一个指向字符串的指针,没有任何额外与数组相关的信息,因此sizeof作用于上只将其当做指针看,一个指针为4个字节,因此返回4.


14 

void main() {
cout<<"this is a string"
}
错误2处。第一个是程序中用到输出对象cout,则必须在程序首部加上文件包含语句:#include<iostream.h>;第二个语句结束必须有结束符”;‘


15 

#include<iostream.h>
void main() {
cin>>x;
int p=x*x;
cout<<"p=<<p<<\n";
b=变量必须先定义后使用,而x未定义就输入值是错误的。如果程序要输出p的值,括号位置是不对的,第二个语句应写为cout<<"p="<<p<<"\n";


16

#include<iostream.h>
void main() {
	int i,j;
	i=5;
	int k=i+j;
	cout<<"i+j"<<k<<"\n";
}
变量必须先定义后使用。因为j未初始化,k的结果不可预料。


17 

#define Max_CB 500
void LmiQueryCSmd(struct MsgCB *pmsg) {
	unsigned char ucCmdNum;
	//...
	for(unCmdNum=0;ucCmdNum<Max_CB;ucCmdNum++) {
		//...
		;
	}
}
会造成死循环,unsigned int的取值范围是0~255。


18 分析下列代码

swap(int *p1,int *p2) {
int *p;
*p=*p1;
*p1=*p2;
*p2=*p;
}
在swap函数中,p是一个“野”指针,有可能指向系统区,导致程序运行的崩溃。在VC++中DEBUG运行时提示错误“ACCESS  Violation”。程序应该改写为:

swap(int * p1,int *p2) {

int p=*p1;

*p1=*p2;

*p2=p;

}


19 分析下列代码

char *s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);
"AAA"是字符串常量,s是指针,指向这个字符串常量,所以声明s的时候就有问题。

正确的声明方式为:const char *s="AAA";

然后又因为是常量,所以对s[0]的赋值操作是不合法的


20 分析下列代码

#define SQUARE(a) ((a)*(a))
int a=5;
int b;
b=SQUARE(a++);
程序本身没有问题,只是计算完成之后,a的值等于7了。



《C/C++程序员面试宝典》 P266~ P276 梁振宇





  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值