C语言-经典问题-持续更新

来源:互联网 发布:跳跃网络版权 编辑:程序博客网 时间:2024/05/19 14:53

1、程序的局部变量存在于(栈区)中,全局变量存在于(数据区)中,动态申请数据存在于(堆区)中。


2、设有以下说明和定义:


则语句 printf("%d", sizeof(struct date)+sizeof(max)); 的执行结果是:___52____

        data是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20 

        data是一个struct, 每个变量分开占用空间. 依次为int4 + DATE20 + double8 = 32.所以结果是 20 + 32 = 52


3、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

        #define  SECONDS_PER_YEAR  (60 * 60 * 24 * 365)UL

        1#define语法的基本知识(例如:不能以分号结束,括号的使用,等等) 

        2)懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。

        3意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。 

        4)如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要


4、写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个。

        #define MIN(A, B)  ((A) <= (B) ? (A) :(B))  

        1)标识#define在宏中应用的基本知识。这是很重要的。因为在嵌入(inline)操作符变为标准C的一部分之前,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。 

        2)三重条件操作符(三目运算符)的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。 

        3)懂得在宏中小心地把参数用括号括起来,因为#define仅仅做替换,如果我们写 #define MULa,b a/b的话,那么我写MULa+1b-1)替换之后的表达式就为a+1/b-1,这个结果显然是违背我们定义的目的的。


5、关键字static的作用是什么?

        1static修饰局部变量:改变局部变量的存储位置(栈区-->数据区),从而改变局部变量的生命周期;(且,被static修饰的局部变量只能被初始化一次)。

        2static修饰全局变量:限制全局变量在本文件中使用,其他文件不能访问(相当于隐藏,且只能初始化一次

        3static修饰函数: static函数在内存中只有一份,限制函数在本文件中使用,而其他文件不能访问;(相当于隐藏)

        static  int a[10]static修饰的数组不初始化时,系统默认初始化为0

        static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;

        static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;

        static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。

6、关键字const的含义及作用。

        const声明一个只读变量,可用于修饰指针,变量,形参等等   修饰数据类型

        const int a; <==>  int const a;

        修饰变量常整形数(不能通过变量名修改a的值,但可以通过指针来强制修改)

        const int *a (int const *a); //const修饰指针指向的内容,表示不希望通过指针修改指向这个空间的值。

        int * const a; //一个指向整型数的常指针,指针指向的整型数是可以修改的,但指针的指向是不可修改的

        int const * a  const; //一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)

        本质:const在谁后面谁就不可修改,const在最前面则将其后移一位即可,二者等效  !!!!!

        const关键字作用:

                1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;

               2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const

               3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;

                4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;

 

7、关键字volatile有什么含意?并给出三个不同的例子

        保证CPU每一次都去内存中读取数据,防止编译器优化;

        一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新从内存中读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 

        内存写入寄存器一般开始写一次,但是valatile修饰之后,每次都会重新读取

        1并行设备的硬件寄存器(如:状态寄存器) 

        2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

        3)多线程应用中被几个任务共享的变量


8、在32位的X86系统下,输出的值为多少?(小端存储)

#include <stdio.h>int main(){int a[5] = {1, 2, 3, 4, 5};int *ptr1 = (int *)(&a + 1);int *ptr2 = (int *)((int)a + 1);printf("%d, %x", ptr1[-1], *ptr2); return 0;}
        答案:  5   2000000             


分析:

        大端存储: 即数据的高字节保存在内存的低地址处,而数据的低字节则保存在内存的高地址处。

        小端存储: 即数据的高字节保存在内存的高地址处,而数据的低字节则保存在内存的低地址处。

        首先 对于数组名而言, a    &a都指向数组首地址,但是其操作宽度不同!

                a + 1  指向 a[1] 的地址,所以也有操作  *(a + 1) 来获得a[1]的值。操作空间为 sizeof(int)

                &a + 1 指正数组的最后,已经指向了数组外。操作宽度即整个数组空间

        然后看题:

                (int *)(&a + 1)  此处(int *)做强制类型转换,将原先的操作宽度变为 4个字节(sizeof(int)),

                        所以ptr1[-1] 则指向数组a最后一个元素,即为 5.

                (int)a + 1  此处将地址强制转换成一个整型数,然后进行+1操作,即指向图中所示的102地址处。

                (int *)((int)a + 1)  此处外层(int *)  将上一行的整型数强制转换成int指针,所以他指向图中红色框区域。

                        由于是小端存储,则打印处ptr2的值为2000000


9、32位系统下,请问如下语句的值

unsigned char *p1;unsigned long *p2;p1=(unsigned char *)0x801000;p2=(unsigned long *)0x810000;
请问  p1 + 5 = ?       p2 + 5 = ?

首先,32位系统下 (unsigned char *) 长度为1个字节,操作宽度为1个字节

                                      (unsigned int *) 长度为4个字节,操作宽度为4个字节

        因此,p1 + 5 = 0x801005             p2 + 5 =0x810014


10、 int i = 10,  j = 10, k = 3; k *= i+j;  k最后的值是?  ---60

        考察优先级,实际写成: k *= (i+j);赋值运算符优先级最低

11、 #define DOUBLE(x)  x+x ,i = 5*DOUBLE(5); i 是多少?    ---30

        #define -----> 仅做替换    即 i = 5 * 5 + 5


12、 下面程序的输出是_____,为什么?

char *ptr;if ((ptr = (char *)malloc(0)) == NULL){    puts("Got a null pointer");}else{    puts("Got a valid pointer");}
       

        输出: Got a valid pointer

        实际上malloc(0)的返回值可能是NULL也可能不是NULL,和实参为一个正整数时没什么区别。如果返回值不为NULL,也应该用free()函数释放。malloc(0)唯一不同的地方就是,就算你申请内存成功,即malloc(0)返回值不为NULL,你也没法使用这块内存。

        详细解析请移步博客:http://www.cnblogs.com/wuyuegb2312/p/3219659.html

13、 局部变量能否和全局变量重名?

         能,局部会屏蔽全局。要用全局变量,需要使用"::"

        局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。如果需要用全局变量,则需要使用指针才能访问

        对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内


14、  如何引用一个已经定义过的全局变量?

        extern 

        可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错


15、 全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?

        可以,在不同的C文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错


16、 下面的函数有什么错误:

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的值可能被意想不到地该变,因此ab可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下: 

                long square(volatile int *ptr) 

                

                                int a; 

                                a = *ptr; 

                                return a * a;

                }


17、 要对绝对地址0x100000赋值,我们可以用 (unsigned int*)0x100000 = 1234; 那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?
        *((void (*)( ))0x100000 ) ( ); 

        1、首先要将0x100000强制转换成函数指针,即: 
                (void (*)())0x100000 
        2、然后再调用它: 
                *((void (*)())0x100000)(); 
        3、用typedef可以看得更直观些: 
                typedef void(*)() voidFuncPtr; 
                *((voidFuncPtr)0x100000)();


- - - - - - - - - - - - - - -- - - - - - - - - - - - - - -  >  持续更新 < - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 


原创粉丝点击