我与阿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 指向另一个整数。

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

    相关推荐

    点赞 评论 收藏
    分享
    避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
    qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
    点赞 评论 收藏
    分享
    不愿透露姓名的神秘牛友
    07-08 17:10
    点赞 评论 收藏
    分享
    评论
    2
    1
    分享

    创作者周榜

    更多
    牛客网
    牛客网在线编程
    牛客网题解
    牛客企业服务