1.以下程序的运行结果是()
#include <stdio.h>
int main() {
int sum, pad,pAd;
sum = pad = 5;
pAd = ++sum, pAd++, ++pad;
printf("%d\n",pAd);
}
答案为7
由于赋值运算符的优先级高于逗号表达式,因此pAd = ++sum, pAd++, ++pad;等价于(pAd = ++sum), pAd++, ++pad; sum 先自增然后赋值给 pAd,pAd 为 6,然后 pAd 自增变为 7。逗号表达式的结果为最后一个表达式的值,因此正确答案为 7。
2.哪一句会出错?
char* s="AAA"; //1
printf("%s",s); //2
s[0]='B'; //3
printf("%s",s); //4
第3句
初始化指针时所创建的字符串常量被定义为只读。如果试图通过指针修改这个字符串的值,程序就会出现未定义的行为。S[0]只可读,不可写
3.对于如下C语言函数:fun(5)的结果为()
int fun (int n) {
int x = 1, k;
if (n == 1) return x;
for(k = 1; k < n; ++k)
x = x + fun(k) * fun(n - k);
return x;
}
答案为51
4.以下程序的输出结果为
#include <stdio.h>
int func(int x, int y) { return (x + y); }
int main() {
int a = 1, b = 2, c = 3, d = 4, e = 5;
printf("%d\n", func((a + b, b + c, c + a), (d, e)));
return 0;
}
答案为9
逗号表达式是一组由逗号分隔的表达式,这些表达式是从左向右计算。逗号表达式的结果是其最后边表达式的值,如果最后边的操作数是左值,则逗号表达式的值也是左值。此类表达式通常用于for循环。
5.若有int w=1, x=2, y=3, z=4;则条件表达w < x ? w : y < z ? y : z的值是3.
答案为 错误
因为条件运算符的结合方向是从右往左的。所以上述表达式的值应当先计算后面那个条件运算符:?的值,即w<x?w:(y<z?y:z)。因此执行顺序为:因为y小于z为真,因此 w<x?w:y,因为w小于x为真,因此表达式的值为w。
6.下列代码运行出错,可能会是哪一行引起的?
void getMemory(char *p) {
p = (char *)malloc(100); // 1
}
int main(int argc, char const *argv[]) {
char *str = NULL;
getMemory(str);
strcpy(str, "hello wrold"); // 2
printf("%s\n", str); // 3
free(str); // 4
}
第2句
1)调用getMemory(str)后,str并未产生变化,依然是NULL(由于str是按值传递的)。只有形参p指向了一块新申请的空间。
2)程序运行到strcpy( str, “hello world” );处将产生错误
7.以下程序的输出结果是()
int main() {
int s, i;
for(s = 0, i = 1; i < 3; i++, s += i);
printf("%d\n", s);
}
答案为5
逗号运算符是由多个表达式构成的,而不是整体看成一个表达式,即i++是一个表达式,s += i也是一个表达式,所以在执行s += i之前,i已经完成了一次自增。
(1)如果for后面没有分号,printf这句话就是for里面的语句。就会先执行printf再执行转化条件。
则先执行循环初试条件s=0,i=1,判断1<3,输出0,执行转化条件i=2,s=2。此时回到判断2<3,输出2。i=3,s=5。再判断3<3为0,跳出循环。
(2)现在题目在for后有分号,则for里面是空语句,先s=0,i=1,控制条件1<3结果为1,执行第二个分号后的句子,因为i++后面有逗号,所以i已经加了1,s加的是经过+1后的i,i=2,s=2。第二次循环2<3成立,i=3,s=2+3=5。第三次3<3判断结果为0,循环结束。但因为第二次循环的转化条件已经执行了。所有输出的是5。
8.对于下面代码段y的值为( )
int x = 3, y = 3;
int t = ++x || ++y;
答案为3
有两个坑,第一,求的是y而不是t 第二,或运算里,左侧是1右边就不执行,与运算类似。
当解析器遇到了||时,只要前面的++x为真,后面的语句就不执行了。
9.写出下列程序在X86上的运行结果
struct mybitfields
{
unsigned short a : 4;
unsigned short b : 5;
unsigned short c : 7;
} test
void main(void)
{
int i;
test.a = 2;
test.b = 3;
test.c = 0;
i = *((short *)&test);
printf("%d\n", i);
}
答案为50
由栈的基本知识(高到低),栈上分配的空间顺序是:c,b,a
定义结构体里面用到的冒号的含义相当于分配几位空间,也即在定义结构体的时候,分配的成员a 4位的空间, b 5位,c 7位,一共是16位,正好两个字节。示意:
test.a 0 0 1 0
test.b 0 0 0 1 1
test.c 0 0 0 0 0 0 0
所以全部总和起来:0000 0000 0011 0010
在执行i=*((short *)&test); 时,取从地址&test开始两个字节(short占两个字节)的内容转化为short型数据,即为0x0032,再转为int型为0x00000032,即50
10.在Windows 32位操作系统中,假设字节对齐为4,对于一个空的类A,sizeof(A)的值为()?
答案为1
类的实例化是在内存中分配一块地址,每个实例在内存中都有独一无二的二地址。同样,空类也会实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化后就有独一无二的地址了。所以,空类的sizeof为1,而不是0.
多重继承的空类的大小也是1.
11.函数的形式参数隐含的存储类型说明是()
答案为auto
函数的隐含储存类型是extern,函数的形参或变量的储存类型为auto
12.若已定义的函数有返回值,则以下关于该函数调用的叙述中错误的是()
答案为:函数调用可以作为一个函数的形参
返回值存在寄存器中,没有地址,不能作为形参,但可以作为实参。
13.在头文件及上下文均正常的情况下,下列代码的运行结果是()
int a[] = {1, 2, 3, 4};
int *b = a;
*b += 2;
*(b + 2) = 2;
b++;
printf("%d,%d\n", *b, *(b + 2));
答案为2,4
从第一步开始
*b+=2;// *b=b+2;
是将b指向地址的值加了2,就是a[0]=3
*(b+2)=2;
等价a[2]=2。
数组变成a[4]={3,2,2,4}
b++;
b指向a[1];
当b++时,指针指向的第二个元素的地址,b=2,b+2后指针指向第四个元素,(b+2)=4;
14.以下叙述中不正确的是()
C程序中的#include和#define均不是C语句(这句正确)
在C程序中,赋值运算符的优先级最低(这句错误)
答案为:c语言中,逗号优先级最低。 用分号;结尾的才看成是C语句
一共有十五个优先级:
1 () [] . ->
2 ! ~ -(负号) ++ – &(取变量地址)* (type)(强制类型) sizeof
3 * / %
4 + -
5 >> <<
6 > >= < <=
7 == !=
8 &
9 ^
10 |
11 &&
12 ||
13 ?:
14 = += -= = /= %= |= ^= &= >>= <<=
15 ,
括号成员第一; //括号运算符 成员运算符. ->
全体单目第二; //所有的单目运算符比如++、 --、 +(正)、 -(负) 、指针运算、&
乘除余三,加减四; //这个"余"是指取余运算即%
移位五,关系六; //移位运算符:<< >> ,关系:> < >= <= 等
等于(与)不等排第七; //即== 和!=
位与异或和位或,“三分天下”***十; //这几个都是位运算: 位与(&)异或(^)位或(|)
逻辑或跟与,十二和十一; //逻辑运算符:|| 和 &&,注意顺序:优先级(||) 低于 优先级(&&)
条件高于赋值, //三目运算符优先级排到13 位只比赋值运算符和","高
逗号运算级最低! //逗号运算符优先级最低
15.对于int *pa[5];的描述,正确的是()
pa是一个具有5个元素的指针数组,每个元素是一个int类型的指针;
看定义记得注意优先级,
int pa[5],首先[]优先级比高,所以pa与[]先结合,pa[5]表明pa是一个数组,大小是5,既然知道pa是数组了,接下来就是确认数组元素了,int*表明数组元素是指针;
int(p)[5],首先()优先级比[]高,所以pa先与结合,*pa表明pa是一个指针,既然知道pa是指针,接下来确认指针指向的数据类型,int [5]表明指针指向大小为5的int型数组。
16.若有代码段
int *p = (int *)malloc(sizeof(int));
则向内存申请到的内存空间中存入整数123的语句为( )
scanf(“%d”, p);
17.下列关于const关键字的说法错误的是:
推荐使用以下方面定义类成员数组: class A{ … const size_t SIZE=100; int _array[SIZE]; };
静态整型常量数据成员)才能在类内初始化,const 不可以 类型 初始化方式 类内 ( 声明 ) 类外 ( 类实现文件 ) 构造函数中 构造函数的初始化列表 非静态非常量数据成员 N N Y Y 非静态常量数据成员 N N N Y (must) 静态非常量数据成员 N Y (must) N N 静态常量数据成员 Y Y N N
18.已知:int x,y;double z;以下语句中错误的函数调用是()
scanf(“%x%o%6.2f",&x,&y,&z);
scanf中的格式控制符不能指明浮点数的精度,D中%6.2f是错误的。
19.下列代码运行出错,可能会是哪一行引起的?
void getMemory(char *p) {
p = (char *)malloc(100); // 1
}
int main(int argc, char const *argv[]) {
char *str = NULL;
getMemory(str);
strcpy(str, "hello wrold"); // 2
printf("%s\n", str); // 3
free(str); // 4
}
答案:2
首先,指针也是一个变量,保存的是一个整数,代表内存地址,str指针的初始值为NULL,NULL代表空指针,空指针是不指向任何内存地址的指针,题目中对str指针进行了参数传递,在C语言中,参数传递是值传递,也就是说,getMemory中的形式参数p是str指针的拷贝,经过getMemory函数的调用后,只是改变了p的指向,并不会改变str指针的指向,str指针在经过getMemory函数的调用后仍然是一个空指针,对空指针进行操作会导致未定义的结果,可能只是运行结果错误,甚至可能导致程序崩溃。
20.下面叙述错误的是()
char acX[]="abc";
char acY[]={'a','b','c'};
char *szX="abc";
char *szY="abc";
答案:szX的内容修改后,szY的内容也会被更改
acX , acY 是2个数组,属于变量,一般存在栈区,可以修改, szX , szY 是2个指针指向常量区,常量区的东西不能被修改,所以D是错误的
21.在VC6.0中,运行下面程序的输出结果是()
#include <stdio.h>
#include <stdlib.h>
void MallocMem(char* pc) {
pc = (char*) malloc (100);
return;
}
int main() {
char *str=NULL;
MallocMem(str);
strcpy(str,"hello ");
strcat(str+2, "world");
printf("%s",str);
return 0;
}
答案:程序运行时崩溃
注意:形参char* , 传入的实参也是char类型,属于值传参,所以并不会改变实参,main中的str没有分配空间,属于野指针(没有开辟内存),对其操作会报错 正确操作: (1)形参为char*,实参为char* (2)形参为引用char* & ,实参为char*
22.下列关于内存分配和释放的函数及其区别描述正确的有?
A
C++语言的标准内存分配函数:malloc,calloc,realloc,free等。
B
C语言的标准内存分配函数为new/delete。
C
malloc和calloc的区别是1块与n块的区别和初始化
D
realloc调用形式为(类型*)realloc(*ptr,size):将ptr内存大小扩容到size。
答案:CD
- malloc,calloc,realloc,free属于C函数库,而new/delete则是C++函数库;
- 多个-alloc的比较:
alloc:唯一在栈上申请内存的,无需释放;
malloc:在堆上申请内存,最常用;
calloc:malloc+初始化为0;
realloc:将原本申请的内存区域扩容,参数size大小即为扩容后大小,因此此函数要求size大小必须大于ptr内存大小。
23.以下程序段执行后结果是()
#include<stdio.h>
int main(){
short *p,*q;
short arr[15] = {0};
p = q = arr;
p++;
printf("%d,", p - q);
printf("%d,", (char*)p - (char*)q);
printf("%d", sizeof(arr) / sizeof(*arr));
}
答案:1,2,15
指针自增、自减每次移动的偏移量是指针所指向对象的字节大小,所以p++与q的偏移量是2个字节。
指针相减的值是指针地址的偏移除以指针每次移位的大小;
1)p-q=1;偏移量为2个字节,每次移动2个字节,所以为1
2)(char *)p-(char
)q,指针的偏移没变,但是每次指针移位是按照(char)类型移动,即每次移动1个字节,所以是2
3)数字每次元素2个字节,所以sizeof(arr)为30,sizeof(*arr)为2。
24.C++里面如何声明const void f(void)函数为C程序中的库函数
答案:extern “C”
25.C语言程序能够在不同的操作系统下运行,这说明C语言具有很好的()
答案:移植性
在硬件系统中用的是兼容性,在软件系统中用的是移植性,涉及到专业术语的不同。
26.下面程序的功能是从输入字符串中找出最长字符串,则下面程序哪行存在错误()
#include "stdio.h"
#include "string.h"
#define N 10
int main()
{
char s[N][81], * t; // line:1
int j; // line:2
for (j=0; j<N; j++) // line:3
gets (s[j]); // line:4
t= *s; // line:5
for (j=1; j<N; j++) // line:6
if (strlen(t)<strlen(s[j])) // line:7
t=&s[j]; // line:8
printf("strings is: %d, %s\n", strlen(t), t); // line:9
}
答案:line:8
其实二维数组名的数据类型就是type(*arrayName)[column],即一个二级指针,所以将一个二级指针赋值给一级指针需要对二级指针变量使用指针运算符;而s[j]就是相当于一个行指针是一个一级指针,所以将一个一级指针赋值给一级指针不用取地址运算符;。
t= *s;
t=s[j];
27.以下描述错误的是:
若一个函数(非主函数)没有return语句,返回类型是void
构造函数和析构函数都没有返回类型,也没有return语句