小知识汇总

来源:互联网 发布:java为app接口开发实例 编辑:程序博客网 时间:2024/05/18 03:17

参考《C语言终极面试宝典》

         《C深度》

描述内存分配方式以及它们的区别?

答:1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。
2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。
3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多

 

请说出const与#define 相比,有何优点?

答:Const作用:定义常量、修饰函数参数、修饰函数返回值三个作用。被Const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
      2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。

NULL和NUL

    很多系统下除了有NULL外,还有NUL(Visual C++ 6.0上提示说不认识NUL)。NUL是ASCII码表的第一个字符,表示的是空字符,其ASCII码值为0。其值虽然都为0,但表示的意思完全不一样。同样,NULL和0表示的意思也完全不一样。一定不要混淆。另外还有初学者在使用NULL的时候误写成null或Null等。这些都是不正确的,C语言对大小写十分敏感啊。当然,也确实有系统也定义了null,其意思也与NULL没有区别,但是你千万不用使用null,这会影响你代码的移植性。

即:

    1、NULL用于表示什么也不指向,也就是空指针((void *)0)    #define NULL 0

    2、0可以被用于任何地方,它是表示各种类型零值的符号并且编译器会挑出它

    3、'\0'应该只被用于结束字符串

    4、NUL没有被定义于C和C++,它不应该被使用除非你自己定义它,像:#define nul '\0'

无法向函数传递一个数组

    void fun(char a[10])
    {
        int i = sizeof(a);
        char c = a[3];
    }
    如果数组b真正传递到函数内部,那i的值应该为10。但是我们测试后发现i的值竟然为4!
    因为:C语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。
    同样的,函数的返回值也不能是一个数组,而只能是指针
    所以替代的正确的写法如下:
    void fun(char *p)
    {
        char c = p[3];//或者是char c = *(p+3);
    }

函数形参只是一份拷贝

    在C语言中,所有非数组形式的数据实参均以传值形式(对实参做一份拷贝并传递给被调用的函数,函数不能修改作为实参的实际变量的值,而只能修改传递给它的那份拷贝)调用。
   如下:
    void fun(char *p)
    {
        char c = p[3];//或者是char c = *(p+3);
    }
    int main()
    {
        char *p2 = “abcdefg”;
        fun(p2);
        return 0;
    }
    这个函数调用,真的把p2本身传递到了fun函数内部吗?
    p2是main函数内的一个局部变量,它只在main函数内部有效。(这里需要澄清一个问题:main函数内的变量不是全局变量,而是局部变量,只不过它的生命周期和
全局变量一样长而已。全局变量一定是定义在函数外部的。初学者往往弄错这点。)既然它是局部变量,fun函数肯定无法使用p2的真身。
    其实是对实参p2做一份拷贝并传递给被调用的函数。即对p2做一份拷贝,假设其拷贝名为_p2。那传递到函数内部的就是_p2而并非p2本身。
    又如:
    void GetMemory(char * p, int num)
    {
        p = (char *)malloc(num*sizeof(char));
    }
    int main()
    {
        char *str = NULL;
        GetMemory(str,10);
        strcpy(str,”hello”);
        free(str);//free并没有起作用,内存泄漏
        return 0;
    }
    在运行strcpy(str,”hello”)语句的时候发生错误。这时候观察str的值,发现仍然为NULL。也就是说str本身并没有改变,我们malloc的内存的地址并没有赋给str,而是赋给了_str。而这个_str是编译器自动分配和回收的,我们根本就无法使用。所以想这样获取一块内存是不行的。那怎么办? 两个办法:
    第一:用return。
    char * GetMemory(char * p, int num)
    {
        p = (char *)malloc(num*sizeof(char));
        return p;
    }
    int main()
    {
        char *str = NULL;
        str = GetMemory(str,10);
        strcpy(str,”hello”);
        free(str);
        return 0;
    }
    第二:用二级指针。
    void GetMemory(char ** p, int num)
    {
        *p = (char *)malloc(num*sizeof(char));
        return p;
    }
    int main()
    {
        char *str = NULL;
        GetMemory(&str,10);
        strcpy(str,”hello”);
        free(str);
        return 0;

    }

宏相对函数优点

    老的C语言程序员中有一种倾向,就是把很短的执行频繁的计算写成宏,而不是定义为函数。完成I / O的g e t c h a r,做字符测试的i s d i g i t都是得到官方认可的例子。人们这样做最根本的理由就是执行效率:宏可以避免函数调用的开销。

c = a+++b;

 int a = 5, b = 7, c;
    c = a+++b;

    上面的代码被处理成:c = a++ + b;
原创粉丝点击