我与阿C的纸短情长(二)

1.普通函数与宏函数的区别

1.编译时机:普通函数在编译时被编译器处理,函数调用会被替换为对函数的实际调用。宏函数在预处理阶段被处理,宏会在代码中被简单地展开,而不是被调用。

2.参数处理:普通函数的参数会被求值一次,且类型会被检查。宏函数的参数在展开时直接替换到宏定义中,不会进行类型检查,可能导致意外的行为。

3.代码大小:普通函数会生成独立的函数代码,增加了代码段的大小。宏函数在展开时直接将代码插入到调用点,避免了函数调用的开销,但可能会导致代码膨胀。

4.调试:普通函数有明确的函数调用栈,方便调试。宏函数在展开后,调试时可能会出现调试信息与源代码不匹配的情况。

5.作用域:普通函数有自己的作用域,不会影响其他代码。宏函数在展开时直接替换,可能会对代码的作用域造成影响。

2.C语言的基本类型有哪些(32位系统),占用字节空间数(要熟练)

char

1

short int

2

int/long int

4

char * /int * /任何的指针

4

float

4

double

8

3.头文件#ifndef/#define/#endif的作用

  • #ifndef:用于判断当前头文件是否已经被包含。
  • 如果该宏之前没有被定义过,则继续编译下面的代码。
  • 如果该宏之前已被定义过,则跳过下面的代码,直接到 #endif。
  • #define:用于定义一个宏。
  • 通过定义一个特定的宏名称,例如MY_HEADER_H表示头文件已被包含。
    • #endif:用于结束 #ifndef / #define / #endif 块。
    • 标记了头文件的结束位置。

    通过使用这种组合,可以防止同一个头文件被多次包含,以避免重复定义和编译错误。

    举例:

    #ifndef MYHEADER_H     // 如果 MYHEADER_H 还没有被定义
    #define MYHEADER_H     // 定义 MYHEADER_H
    
    void sayHello();       // 函数声明
    
    const int MAX_VALUE = 100;  // 常量定义
    
    #endif               // 结束条件编译
    
    上述是一般的使用模板
    

    4.如何判断大小端?

    #include <stdio.h>
    
    int check_endianness() {
        unsigned int num = 1;
        char *ptr = (char *)#
        
        if (*ptr) {
            return 1; // 小端序
        } else {
            return 0; // 大端序
        }
    }
    
    int main() {
        if (check_endianness()) {
            printf("This system is little-endian.\n");
        } else {
            printf("This system is big-endian.\n");
        }
    
        return 0;
    }
    
    

    在这段代码中,我们创建了一个无符号整数num并将其地址转换为指向字符的指针ptr。由于内存中存储数据的方式取决于系统的字节序,我们可以通过检查该指针指向的第一个字节来判断系统的字节序。如果第一个字节存储的是1,则说明系统是小端序;如果第一个字节存储的是0,则说明系统是大端序。

    5.内存泄漏和内存溢出是什么?

    (1)内存溢出:指程序申请内存时,没有足够的内存供申请者使用。或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错Out Of Memory,即所谓的内存溢出。

    (2)内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间。一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。

    6. strcpy和memcpy区别

    1.复制的内容不同。

    • strcpy只能复制字符串,
    • memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。

    2.复制的方法不同。

    • strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,如果空间不够,就会引起踩内存。
    • memcpy则是根据其第3个参数决定复制的长度。

    3.用途不同。

    • 通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy,由于字符串是以“\0”结尾的,所以对于在数据中包含“\0”的数据只能用memcpy。

    7.sizeof与strlen的区别

    sizeof:

    • 用于获取数据类型或变量的字节大小。
    • 可以接受多种参数,包括数据类型、变量名、数组名等。
    • 返回的是整个数据类型或变量占用的内存空间大小。

    strlen:

    • 用于获取以’\0’结尾的字符串的实际长度。
    • 在运行时计算,需要遍历字符串的内容来确定长度。
    • 返回的是字符串中的字符个数,不包括字符串结束符’\0’。

    举例:

    char str[] = "Hello";
    size_t size_str = sizeof(str);
    size_t length_str = strlen(str);
    // size_str 的值为 6,因为包括字符串 "Hello" 的 5 个字符和结尾的 '\0',共 6 个字节
    // length_str 的值为 5,因为字符串 "Hello" 有 5 个字符,不包括结尾的 '\0'
    
    

    注意事项:

    • sizeof返回的是静态的大小,而strlen返回的是实际的字符串长度。
    • 在使用strlen时要确保操作的对象是以’\0’结尾的字符串,否则可能出现不确定的结果。
    • sizeof可以用于任何数据类型或变量,而strlen只适用于字符串。

      8.结构体和共用体的区别:

    结构体(struct)和共用体(union)是在C和C++等编程语言中用来组织和存储数据的重要概念,它们之间有几个关键的区别:

    1.结构体(struct):

    • 结构体是一种用户自定义的数据类型,可以包含多个不同类型的成员变量。
    • 结构体的各个成员在内存中是按照定义的顺序依次存储的,每个成员有自己的内存空间。
    • 结构体的大小等于其所有成员变量大小之和,可能会有内存对齐的问题。
    • 结构体的各个成员可以同时被访问和操作。

    2.共用体(union):

    • 共用体是一种特殊的数据结构,所有成员共享同一块内存空间。
    • 共用体的大小等于其最大成员的大小,因为共用体中只有一个成员可以被同时使用。
    • 当一个共用体的成员被赋值后,其他成员的值会被覆盖,因为它们共享同一块内存空间。
    • 共用体通常用于节省内存空间,或者在需要在不同类型的数据之间进行转换时使用。

    9.一个指针可以是volatile吗

    一个指针可以被声明为volatile。在C和C++中,volatile是一个关键字,用于告诉编译器不要对声明为volatile的变量进行优化,因为这些变量的值可能在程序的控制之外被改变。

    当一个指针被声明为volatile时,意味着指针所指向的数据是volatile的,即这些数据可能会在程序的执行过程中被外部因素改变,如硬件中断、多线程操作等。因此,编译器不应该对这些数据的读写进行优化,而应该每次都从内存中读取或写入数据。

    示例:

    volatile int *ptr; // 声明一个指向volatile int的指针
    
    int main() {
        int a = 10;
        ptr = &a;
    
        // 在程序的其他地方可能会改变a的值,编译器不能对ptr所指向的数据做优化
        // 因此,每次访问*ptr时都应该从内存中读取a的值
        int b = *ptr; // 从内存中读取a的值
    }
    
    

    10.常见变量定义以及解释:

    • int a; // 定义一个变量 a,类型为 int
    • int *ptr_a;// 定义一个指针 a,指向 int 类型的变量
    • int **ptr_ptr_a;// 定义一个指针 a,指向一个指向 int 类型的指针
    • int arr[10];// 定义一个数组 a,有 10 个元素,每个元素是 int 类型
    • int *ptr_arr[10];// 定义一个数组 a,有 10 个元素,每个元素是 int 类型的指针
    • int (*ptr_to_arr)[10];// 定义一个指针 a,指向一个数组,该数组有 10 个元素,每个元素是 int 类型
    • int (*ptr_to_func)(int);// 定义一个指针 a,指向一个参数是 int,返回值是 int 的函数
    • int (*arr_of_func[10])(int);// 定义一个数组 a,每个元素是一个指向参数是 int,返回值是 int 的函数指针

    11.说说下面表达式的区别

    1. const int* p;
    2. int* const p;
    4. int const *p;
    5. const int* const p;
    
    1. const int* p;  这表示指针 p 指向一个常量整数。这意味着你不能通过 p 修改所指向的整数的值,但是你可以改变 p 指向另一个整数。
    2. int* const p; 这表示 p 是一个指向整数的常量指针。这意味着你可以通过 p 修改所指向的整数的值,但是你不能改变 p 指向另一个整数。
    3. int const *p; 这和第一个声明 const int* p; 是等价的,表示指针 p 指向一个常量整数。
    4. const int* const p; 这表示 p 是一个指向常量整数的常量指针。这意味着你既不能通过 p 修改所指向的整数的值,也不能改变 p 指向另一个整数。

    #面经##嵌入式##面试#
    全部评论

    相关推荐

    10-31 12:21
    已编辑
    门头沟学院 市场
    #非技术面试记录#&nbsp;港股上市企业,主要是一些小家电业务,空气净化器,厨房电器等…这个岗位是计划和采购履行结合的一个岗位,工作内容肯定会比较多。面试共三个环节,以下是面试问题:第一环节:面试官介绍公司,目前面试官的企业里为数不多会先介绍自己公司的企业了(大部分公司都认为我们投了他们,就必须对他们公司业务非常了解,但现在谁不是海投的)第二环节:1.自我介绍2.问了学校里的一些问题,包括转专业,对专业的认识等等。3.如何体现简历上写的数据分析能力强(面试官说现在很多人都会写这条,但是一问又回答不上来,所以写了这个的伙伴们记得提前想好措辞)4.如何体现你的沟通能力和团队协作能力5.接着上一个问题,换另外一种角度再说明一下6.三到五年的个人规划(面试官说我回答的太官方了,不过确实说的比较笼统)7.对“目标”这个词的认识并且如何去做?反正环节:因为上一个环节回答的比较差,所以就针对规划和目标这两个问题去交流了一下,面试官非常认真的给我解释了如何去做目标以及个人的发展规划,这一趴真的学到非常多东西!!!总结一下,整个过程就是你来我往,非常愉快的氛围,整体就像是在聊天,中间有些问题都是顺着你的回答问的。#秋招[话题]# #研究生[话题]# #面试[话题]# #面试经验[话题]#&nbsp;&nbsp;&nbsp;#面试经验#
    查看6道真题和解析 非技术面试记录
    点赞 评论 收藏
    分享
    不愿透露姓名的神秘牛友
    10-20 23:56
    点赞 评论 收藏
    分享
    2 1 评论
    分享
    牛客网
    牛客企业服务