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 梁振宇