C语言笔试小题目
- 1.bool,float,指针变量与“零值”比较的if语句。
- 2.用Vi编译器底行命令模式实现字符串替换
- 3.i++一下代码的输出结果是
- 4.一下代码为windows NT下32位程序,请计算sizeof的值。
- 5.头文件中的ifndef/define/endif干什么用的?
- 6.嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?
- 7.交换两个数的宏定义
- 8.下面代码输出是什么?为什么
- 9.strlen与sizeof区别
- 10.mystrcpy
- 11.关于动态申请内存的问题
- 12.请问运行Test函数会有什么样的结果?
- 13.请问运行Test函数会有什么样的结果?
- 14.请问运行Test函数会有什么样的结果?
- 15.const是什么含意?
- 16.static的作用是什么?
- 17.volatile有什么含意 并给出三个不同的例子。
- 18.一个参数既可以是const还可以是volatile吗?解释为什么。
- 19.一个指针可以是volatile 吗?解释为什么。
- 20.下面的函数有什么错误:
1.bool,float,指针变量与“零值”比较的if语句。
Bool:
if(flag)
if(!flag)
//if(flagTRUE),if(flag1),if(flagFALSE),if(flag0),这些属于不良风格,不得分。
Float:
if((x>=-0.000001)&&(x<=0.000001))
//不可以将浮点变量用””,”!=”与数字比较,应该设法转化成”<=”,”>=”此类形式,例如if(x0.0) if(x!=0.0),是错误的。
指针:
if(p==NULL)
if(p!=NULL)
//if(p==0),if(p!=0),if§,if(!).不良风格
2.用Vi编译器底行命令模式实现字符串替换
把当前文件中的“xiaodai”全部替换成“banzhang”。
():%s/xiaodai/banzhang/g
3.i++一下代码的输出结果是
int i = 1;
int j = 2;
int k = i+++j;
cout << k << endl;
/*3 i+++j是首先结合为i++(大多数的c编译系统都是尽可能多的将多个字符结合成为一个运算符,所以i+++j等价于(i++)+j),然后再+j;但是i++是事后计算,也就是先计算i+j然后再i++,所以k的值是1+2=3;然后i自增到2*/
4.一下代码为windows NT下32位程序,请计算sizeof的值。
char str[]=”Hello”;
char *P = str;
int n=10;
//请计算
sizeof(str) = ?;
sizeof(p) = ?;
sizeof(n) = ?;
void func(char str[100]){
sizeof(str) = ?;
}
void *p = malloc(100);
sizeof(p) = ?;
答案:6 4 4 4 4,数组名是可以认为是数组第一个元素的首地址,但不是一个真正的地址。
5.头文件中的ifndef/define/endif干什么用的?
防止头文件被重复引用。
6.嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?
while(1){
}
for(;;){
}
loop:
…
goto loop
7.交换两个数的宏定义
交换两个参数值的宏定义为
#define SWAP(a,b) (a)=(a)+(b);(b)=(a)-(b);(a)=(a)-(b);
8.下面代码输出是什么?为什么
void foo(void) {
unsigned int a = 6;
int b = -20;
(a+b > 6)
puts("> 6") : puts("<= 6");
}
这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是“>6”。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。
9.strlen与sizeof区别
注意:strlen求数组长度未计‘\0’.
strlen( )求得的是字符串的长度;sizeof( )计算字符串占的总内存空间。
str[20] = {"abcd"};
strlen(str); //结果为4
sizeof(str); //结果为20
10.mystrcpy
char * strcpy( char *strDest, const char *strSrc ) //3
{
assert( (strDest != NULL) && (strSrc != NULL) );//2
char *address = strDest; //1
while( (*strDest++ = * strSrc++) != '\0' );//3
return address; //1
}
//strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
为了实现链式表达式。
11.关于动态申请内存的问题
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
//请问运行Test函数会有什么样的结果?
传入GetMemory( char *p )函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值,执行完 char *str = NULL; GetMemory( str ); 后的str仍然为NULL;
直白的讲就是函数GetMemory()并没有传参返回。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G1Krtu6u-1631525055073)(C:\Users\BMn94\AppData\Roaming\Typora\typora-user-images\image-20210912173256457.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LJ0oS09Z-1631525055075)(C:\Users\BMn94\AppData\Roaming\Typora\typora-user-images\image-20210912173315679.png)]
12.请问运行Test函数会有什么样的结果?
char *GetMemory(void) {
char p[] = "hello world";
return p;
}
void Test(void) {
char *str = NULL;
str = GetMemory();
printf(str);
}
可能是乱码。char p[] = “hello world”;return p; p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其根源在于不理解变量的生存期。
13.请问运行Test函数会有什么样的结果?
void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
能够输出hello,Test函数中也未对malloc的内存进行释放。 GetMemory避免了以上问题,传入GetMemory的参数为字符串指针的指针,但是在GetMemory中执行申请内存及赋值语句*p = (char *) malloc( num ); 后未判断内存是否申请成功,应加上: if ( *p == NULL ) { …//进行申请内存失败处理 }
void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
if ( *p == NULL ) {
//进行申请内存失败处理
}
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
14.请问运行Test函数会有什么样的结果?
野指针问题
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL)
{
strcpy(str, “world”);
printf(str);
}
}
运行成功,输出可能是乱码,char *str = (char *) malloc(100); 后未进行内存是否申请成功的判断;另外,在free(str)后未置str为空,导致可能变成一个“野”指针,应加上: str = NULL;
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL)
{
str = NULL;
strcpy(str, “world”);
printf(str);
}
}
15.const是什么含意?
const意味着“只读”。
const int a; //a是一个常整型数;
int const a; //a是一个常整型数;
const int *a; //a是一个指向常整型数的指针(整型数是不可修改的,但指针可以);
int * const a; //a是一个指向整型数的常指针(指针指向的整型数是可以修改的,但指针是不可修改的);
int const * a const; //a是一个指向常整型数的常指针(指针指向的整型数是不可修改的,同时指针也是不可修改的);
- 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。)
- 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
- 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。
16.static的作用是什么?
- 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
- 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
- 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
17.volatile有什么含意 并给出三个不同的例子。
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
下面是volatile变量的几个例子:
-
并行设备的硬件寄存器(如:状态寄存器)
-
一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
-
多线程应用中被几个任务共享的变量
18.一个参数既可以是const还可以是volatile吗?解释为什么。
是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
19.一个指针可以是volatile 吗?解释为什么。
是的。尽管这并不很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的指针时。
20.下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
这段代码有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!
正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}