高分救助:帮我答几道C语言题

2024-10-31 03:21:39
有3个网友回答
网友(1):

转贴的,百度可是个好东东^_^

1.1 这道题主要考察#的功能,S是一个表达式。TRACE()的作用就是在DEBUG状态下,计算表达式S的值之前先打印S。

1.2 #error用于向编译器报错,并输出它后面带的错误信息。例如:
#ifndef SOMETHING
#error SOMETHING not defined!
#endif
如果在这段代码之前未定义过SOMETHING,则在编译时出错,并给出"SOMETHING not defined!"的错误信息。

作者: 增压Q因斯坦 2007-1-12 06:20 回复此发言

--------------------------------------------------------------------------------

2 偶素新来的,请吧主多多关照

1.3 #define NELEMENTS(array) (sizeof(array) / sizeof((array)[0]))

1.4 #define OFFSET(structure, member) ((int) &(((structure *)0)->member))

2 (a) An integer:int a;
(b) A pointer to an integer:int *a;
© A pointer to a pointer to an integer:int **a;
(d) An array of 10 integers:int a[10];
(e) An array of 10 pointers to integers:int *a[10];
(f) A pointer to an array of 10 integers:int (*a)[10];
(g) A pointer to a function that takes an integer as an argument and returns an integer:int (*a)(int);
(h) An array of 10 pointers to functions that take an integer argument and return an integer:int (*a[10])(int);

3 char (*(*x())[])();
这道题来自"The C Programming Language"中的一个例子。
首先,确定标识符:x
x是一个函数,没有参数:x()
返回值是一个指针:*x()
这个指针指向一个数组:(*x())[]
数组中的每个元素是指针:*(*x())[]
指向一个不带参数的函数:(*(*x())[])()
函数的返回值是char:char (*(*x())[])()
这里,要知道*、()和[]的优先级。

4 这个定义有点怪,它的意思是:jmp_buf这种类型是一个数组,只有一个元素,元素类型为struct{...}。数组名作为函数参数时,应该是传递地址/指针。

5 在编译源文件时,C编译器和C++编译器都会对符号(函数或变量)名作某些修正,但两者采用的修正方法不同,所以两者生成的目标文件不能互相链接。在C+ +中使用extern "C"可以让C++符号获得C链接特性。由于C++编译器会自动定义__cplusplus宏,所以在C语言头文件中采用这种结构可以保证无论使用何种编译器,生成的目标文件都具有C链接特性,能够与标准C编译器所生成的目标文件相链接。

6 (1)用于全局变量:外部静态变量,只能在本源文件中被引用,不能被其它源文件所引用。
(2)用于局部变量:局部静态变量,在函数返回后存储单元不释放;下一次调用该函数时,该变量为上次函数返回时的值。
(3)用于函数:内部函数,只能被本源文件中的函数所调用,不能被其它源文件调用。

7.1 const关键字在C语言中用于声明"常变量",其值不可修改,但具有确定的数据类型。C编译器总是为其分配相应的存储单元。
在C++中,const关键字用于声明常量,C++编译器视具体情况决定是为其分配存储单元还是仅将其作为编译期间的常量。

7.2 const int a1; a1是整型常量。
int const a2; a2是整型常量。等同于const int a2;
const int *a3; a3是指针(a3是可变的),指向一个整型常量。等同于int const *a3;
int * const a4; a4是常量指针(a4不可变),指向一个整型变量。
int const * const a5; a5是常量指针(a5不可变),指向一个整型常量。等同于const int * const a5;

8.1 volatile关键字用于声明内存映射的易失型变量,这类变量的值随时可能由于某种编译器所不知道的原因(例如,外部设备对其写入)所改变,所以编译器在进行代码优化时不能对其做任何的假设和依赖。

8.2 volatile可以和const一起使用,不过很少见。
const关键字的意思是限制编程者自己不能修改变量的值;两者并不矛盾。
例如一个内存映射的、只读的硬件寄存器,假设它的地址是p,则可以这样声明:volatile const UINT32 *p;

9 sizeof(pmsg) = 指针变量的长度
sizeof(msg) = 2 (字符数组的长度)
sizeof("A") = 2 (字符串的长度)
sizeof(ch) = 1 (字符变量的长度)
sizeof(‘A’) = 整型变量的长度 (在C语言中,字符常量的数据类型实际上是int;在C++中,它的数据类型是char,从而原式等于1)
sizeof(param) = 指针变量的长度 (数组名作参数时,传递的是数组的起始地址)

10 这种写法是和编译器&操作系统相关的,所以不应当这样写。在WIN2K+VC环境下debug程序时会出现异常。

作者: 增压Q因斯坦 2007-1-12 06:20 回复此发言

--------------------------------------------------------------------------------

3 偶素新来的,请吧主多多关照
不过这样写,编译器不会报错。按道理,"hello..."的类型是const char [N],它是不能赋值给char *的,
因为会丢失常量属性。但在const关键字成为C标准之前,大家都这样写程序,所以char *pmsg = "hello..."
这种写法被给予特别豁免,即使在C++中也是如此,在"The C++ Programming Language"的附录里对此有讨论。

"hello, world!"是字符串常量(string literal),它的类型是const char [N],N为字符串的长度(包括结尾的0)。
"The C Programming Language"指出,写字符串常量的结果是未定义的(undefined)。所以在有些平台(操作系统+编译器)
上程序不会出错,而在其它平台上程序出现异常。

GNU手册里这样说:
Writing into string constants is a very bad idea; "constants" should be constant.
不过在GNU中它提供另外的选择:使用-fwritable-strings进行编译就可以。

那么,为什么不允许修改字符串常量呢(它不也在内存中吗)?
这可能和另外一个特点有关,即重复字符串的合并。现在的编译器应该会主动帮助我们合并程序中相同的字符串常量
以节省内存。如果string literal可写,就会出现问题。例如:
void foo()
{
printf("%s\n", "how are you?");
}
void bar()
{
char *p = "how are you?";
strcpy(p, "WHO ARE YOU?");
}
调用foo()当然会打印"how are you"。但如果编译器合并字符串,那么先调用bar(),再调用foo(),foo()打印的就是
"WHO ARE YOU?"。这当然不是我们想要的结果。
另外一方面,这样写也有问题(确实有人这么写):
if (func() == "something")
...
func()是:
char *func()
{
...
return "something";
}
这就假设编译器一定会帮我们合并字符串,然而那也不一定。

11 输出"> 6"。
混合运算时的数据类型转换次序:int --> unsigned --> long --> double。
另外,char和short必定转换为int,float必定转换为double。

12 p = (int *)((unsigned int)a + 1);
代码的意图是想使p指向数组的第二个元素,但通常的写法是:p=a+1。这里存在这样的问题:a是个常量地址,
a+1指向下一个数组元素,而((unsigned int)a + 1)指向下一个内存地址。如果地址是字节计数的,则p指向的
是数组第一个元素的第二个字节。还有一个效果就是:在RISC上该printf语句会出异常,因为不允许非对齐访问
(mis-aligned access)。对齐访问就是访问2字节变量的地址要能被2整除,4字节变量的地址要能被4整除,etc。

13 这些函数到处都查得到,就不用做了吧.

【2 数据声明和定义】

给定以下类型的变量a的定义式:

a) An integer int i = 0;
b) A pointer to an integer int *p = NULL;
c) A pointer to a pointer to an integer int **pp = NULL;
d) An array of 10 integers int a[10];
e) An array of 10 pointers to integers int *pa[10];
f) A pointer to an array of 10 integers int *ap = a;
g) A pointer to a function that takes an integer as an argument and returns an integer int ( *fp)( int )=NULL;
h) An array of ten pointers to functions that take an integer argument and return an integer typedef int( *fptype )( int );
fptype fpa[10];
【3 复杂类型(1)】

有如下表达式:

char (*(*x())[])();

请用文字描述x是什么?

回答:声明x是一个函数指针数组,函数的返回值类型是字符指针,参数为空。

空指针同志在《解释一下 typedef int (*fn_ptr)()》这篇帖子里说过
c专家编程中理解c语言声明的优先级原则,如下:
1) 声明从它的名字开始读取,然后按照优先级顺序依次读取
2) 优先级地从高到低的顺序是
a)声明中括号被括起来的部分
b)后缀操作符:
括号()表示这是一个函数,方括号表示这是一个数组

作者: 增压Q因斯坦 2007-1-12 06:20 回复此发言

--------------------------------------------------------------------------------

4 偶素新来的,请吧主多多关照
c)前缀操作符,*表示这是一个指针
3)如果有const或volatile后面紧跟类型说明符如int等,那么它作用于类型说明符,在其它情况下,const等作用于紧邻的指针星号。
还真派上用场了,特致谢,不知对不对。
【4 复杂类型(2)】

jmp_buf的定义:

typedef struct _jmp_buf
{
REG_SET reg;
int extra[3];
} jmp_buf[1];

setjmp函数的原型:

extern int setjmp (jmp_buf __env);

问:调用setjmp时传递__env的内容,还是传递指针?

答:传递指针。由jmp_buf 的定义来看,它是一个数组类型,并且只含一个元素。由此_env是一个数组,在函数的形参中,任何形式的数组都是指针等价的,传递参数时数组名将转化为相应的指针类型。实际上,在所有表达式中都是如此。
为什么要把jmp_buf定义为数组呢?因为setjmp需要改变__env的内容,这必须要用指针才行。但为什么不直接把参数定义为指针类型而是用这样一种奇特的方法,我也不清楚。

【5 头文件】

问:为什么标准头文件都有类似以下的结构?

#ifndef __INCvxWorksh
#define __INCvxWorksh

#ifdef __cplusplus
extern "C" {
#endif

/*...*/

#ifdef __cplusplus
}
#endif

#endif /* __INCvxWorksh */

这个不太会,但试一试。
答:为了使c++兼容c,在c++中也能调用c的标准库。如果定义了__cplusplus测试宏,则编译时进行extern "C"声明。
#ifndef __INCvxWorksh
#define __INCvxWorksh
这俩是什么不清楚。

【6 static关键字】

请说出static关键字的3种用处:
(1)用于全局变量;
(2)用于局部变量;
(3)用于函数。

/* file.c */
static int a; /* a只能在file.c中被引用*/
int b;

static int fn() /*fn只能在file.c中被引用*/
{
static int x; /* x的生存周期和程序的生存周期一样 */
int y;
}

答:见注释。

7.1 const关键字的意义是什么?
7.2 解释以下的变量定义:
const int a1; //a1为整型常量
int const a2; //同上
const int *a3; //a3整型指针常量,a3本身是个常量
int * const a4; //a4是整型常量指针,a4所指内容是常量
int const * const a5; //a5是整型常量指针常量,a5本身和a5所指内容都是常量
晕了

【9 sizeof()】
有以下定义:

char *pmsg = "A";
char msg[] = "A";
char ch = 'A';

答:
sizeof(pmsg) = 4 //32位编译器
sizeof(msg) = 2 //字符'A'和'\0'
sizeof(“A”) = 2 //同上
sizeof(ch) = 1
sizeof(‘A’) = 1 (在C++中等于多少?)

void f(char param[100])
{
// sizeof(param) = 4 //32位编译器
}
评论Feed

网友(2):

第一题:
printf不用怀疑了吧,cdecl调用,这个是考传参的,从右到左,调用者恢复栈指针,所以*(++ptr)先执行,并push,然后再push *ptr,所以答案是8 8,没问题吧?

第二:

#include
#include

int fun(const char* src)
{
const char* p1 = src;
const char* p2 = src + strlen(src);
if(p1 == p2)
return -1;

while(p1 < p2)
if(*p1++ != *--p2)
return 0;
return 1;
}

int main()
{
printf("%d\n", fun("12321"));
printf("%d\n", fun("123210"));
printf("%d\n", fun(""));
}

第三:

如果定义了DEBUG这个宏,TRACE的作用就是跟踪程序的执行过程,便于查找出错位置,否则TRACE被直接替换为原语句。

第四:#error产生一个特定的编译错误。
比如:
#if xxxx
#error [error description...]
#endif

第五:
#define NELEMENTS(array) (sizeof(array) / sizeof(array[0]))

#define OFFSET(structure, member)\
((int)&(((structure*)0)->member))

第六:
char (*(*x())[])();
x是一个函数,该函数不接受参数,并返回一个指向一个大小未确定的数组的指针,这个数组的元素是:不接受参数,返回一个char类型的函数指针。

举例:

#include
#include

char f1()
{
puts("f1");
return 0;
}

char f2()
{
puts("f2");
return 0;
}

char f3()
{
puts("f3");
return 0;
}

//typedef char (*(*x())[])();

typedef char (*pf[3])();
pf ss = {f1, f2, f3};

// 由于不能定义函数数组,所以这里手动指定数组大小为3
char (*(*x())[3])()
{
return &ss;
}

int main()
{
pf a;

memcpy(a, x(), sizeof(pf));
for(int i = 0; i < 3; ++i)
a[i]();
}

第七:
#ifdef xxx
#define xxx
...
#endif
是为了防止重复包含

之中的
#ifdef __cpluspls
...
#else
extern "C" {
...
}
#endif
是为了区别C代码和C++代码,由于C++的重载和名称空间机制,特别是重载,编译时会给函数加上一些特殊的修饰符,使用extern "C"是为了在连接时使用C连接性来连写该模块的代码,C连接性的特点之一就是保持函数原本的标识符,这可以使C++中的C库函数(加c去.h的那些个文件)在以C++或C方式编译时均可被使用。

第八:

const int a1; // 一个整型常数
int const a2; // 同上
const int *a3; // 一个指向常量的整型指针(目标不可修改)
int * const a4; // 一个指向整型的常量指针(a4指向的位置不可修改,这个必须初始化)
int const * const a5; // 综合上2条

第九:

volatile,一些需要和硬件直接交互的程序,其程序中的某些变量不手程序控制,需要外部设备来负责更新,比如程序中可能存在一个保存并更新系统时钟的变量,这个变量就需要系统来修改。
volatile告诉编译器不要对该对象做一些特殊的优化。

volatile int *p; // 定义一个指向可被外部改变(或不会被编译器优化)的整型数据的指针

volatile能和const一起使用吗?例如
volatile const int *p;

可以

网友(3):

1.这个是由于具体编译器从左向右还是从右向左来决定++i之类的值的,如果是VC,就是从右向左,自然都是指向a[2]。
用DEV C++,就是7,8了,你可以自己下个试试,跟具体编译器有关,考试的话,还是考虑从左向右吧,比较无奈的问题。
2.指针是用来传入字符串的,你可以定义两个指针,分别指向字符串的首尾,然后开始比较,一加一减的移动,直到出现不一致的字符就判断为不是回文。
如*p,*q,*f,*e,f为字符串首,e为尾,初始p=f,q=e
p++==q--;
然后循环。