嵌入式系统:C语言基础(一)

1.static关键字

  • 声明静态变量,使其生命周期延长或作用域限定在当前文件内。
  • 声明静态函数,使其作用域限定在当前文件内。
  • 声明静态成员变量,使其属于类本身而不是对象,多个对象共享同一份内存。
  • 使用静态限定符,控制变量的初始化和生命周期。

举例:

  1. 在函数内部使用 static:
#include <stdio.h>

void increment() {
  static int count = 0;
  count++;
  printf("调用次数:%d\n", count);
}

int main() {
  for (int i = 0; i < 5; i++) {
    increment();
  }
  return 0;
}
在每次调用 increment 函数时,count 的值会持续增加,而不会被重置。
这是因为 count 被声明为 static,其生命周期跨越了函数调用。

2.在文件作用域使用 static:

//这里的例子是防止同学们以后要避免这样去使用。更好的去理解static的隐藏性
// File1.c
static int globalVar = 10; //变量只可在file1.c里使用

// File2.c
extern int globalVar;
int main() {
  printf("globalVar 的值:%d\n", globalVar);
  return 0;
}

在 File1.c 文件中,我们声明了一个具有文件作用域的静态全局变量 globalVar。
在file2里是extern不到。

2.全局变量和局部变量的区别

全局变量:

  • 在函数外部声明的变量,整个程序都可以访问。
  • 声明时会被默认初始化,可以在任何函数中使用。
  • 生命周期长,整个程序执行期间都存在。
  • 全局变量存储在全局数据区(data)中

局部变量:

  • 在函数内部或代码块内部声明的变量,只能在所属的函数或代码块中访问。
  • 声明时没有默认初始化,需要手动赋值才能使用。
  • 生命周期短,只在所属的函数或代码块的执行期间存在。
  • 局部变量存储在栈区(stack)

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

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

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

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

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

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

4.int main(int argc, char ** argv)函数中,参数argc和argv代表什么?

第一个参数,int型的argc,为整型,用来统计程序运行时发送给main函数的命令行参数的个数。

第二个参数,char*型的argv[],为字符串数组,用来存放指向字符串的指针元素,每一个指针元素指向一个字符串参数。

各成员含义如下:

  • argv[0]指向程序运行的全路径名
  • argv[1]指向在DOS命令行中执行程序名后的第一个字符串
  • argv[2]指向执行程序名后的第二个字符串。。。。。。
  • argv[argc-1]指向执行程序名后的最后一个字符串argv[argc]为NULL

5.#include<> 和 #include""的区别

使用 #include<>:

  • 用于包含系统提供的标准库头文件。
  • 在编译器的搜索路径中寻找头文件。
  • 编译器会先在系统的标准头文件目录中查找,如果找不到则报错。

使用 #include"":

  • 用于包含用户自定义的头文件或项目中使用的其他非系统头文件。
  • 在当前源文件的相对路径或指定的绝对路径中寻找头文件。
  • 编译器会首先在当前源文件所在目录中查找,如果找不到再根据指定的路径查找。

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

char

1

short int

2

int/long int

4

char * /int * /任何的指针

4

float

4

double

8

7.头文件#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               // 结束条件编译
    
    上述是一般的使用模板
    

    8.说说数组和指针的区别

    1.概念:

    (1)数组:数组是用于储存多个相同类型数据的集合。 数组名是首元素的地址。

    (2)指针:指针相当于一个变量,但是它和普通变量不一样,它存放的是其它变量在内存中的地址。指针名指向了内存的首地址。

    2.区别:

    (1)赋值:同类型指针变量可以相互赋值;数组不行,只能一个一个元素的赋值或拷贝

    (2)存储方式:​ 数组:数组在内存中是连续存放的,开辟一块连续的内存空间。数组是根据数组的下进行访问的,数组的存储空间,不是在静态区就是在栈上。​ 指针:指针本身就是一个变量,作为局部变量时存储在栈上。

    (3)求sizeof:​ 数组所占存储空间的内存大小:sizeof(数组名)/sizeof(数据类型)​ 在32位平台下,无论指针的类型是什么,sizeof(指针名)都是4,在64位平台下,无论指针的类型是什么,sizeof(指针名)都是8。

    9.如何判断大小端?

    #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,则说明系统是大端序。

    10、内存泄漏和内存溢出是什么?

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

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

    11. strcpy和memcpy区别

    1.复制的内容不同。

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

    2.复制的方法不同。

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

    3.用途不同。

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

    #牛客在线求职答疑中心##面经##嵌入式##春招##23届找工作求助阵地#
    嵌入式知识图谱 文章被收录于专栏

    欢迎来到《嵌入式知识图谱》专栏!这里是一个专注于涵盖C/C++编程、操作系统原理、数据结构算法、计算机网络技术以及嵌入式软件知识的平台。 在本专栏中,我们将分享关于嵌入式系统开发的最新趋势、实用技巧、行业见解以及面试准备建议。无论您是刚入门的学习者还是经验丰富的专业人士,我们都致力于为您提供有价值的内容,帮助您在嵌入式软件领域取得成功。

    全部评论
    觉得文章好的话,帮忙点个赞哦
    点赞 回复
    分享
    发布于 02-29 08:00 北京

    相关推荐

    11 16 评论
    分享
    牛客网
    牛客企业服务