笔记
一、C语言的基础
1.C语言怎么运行?
包含各种库的头文件和库,然后在自己的代码中依赖这个头文件, 并且通过编译器告诉路径, 然后需要知道也能依赖自己项目中的具体实现.c。
2.头文件和库的是啥?头文件和.c 的区别是啥? 如何用库或者说如何用别人给你的库或者gcc自带的库呢?为啥c语言的printf不用指定路径就能找到库的位置?
头文件只是申明, 库是多次利用的一个东西。
头文件一般只是申明,.c文件是具体的宏或者函数的实现。
用的话就是先下载库然后包含头文件, 并且编译的时候告诉库在哪里,
printf不用告诉具体库的路径是因为这些都是在默认链接路径下。
2.。ifndef 的作用?
在C++中, #pragma once 和这个是一样的意思
就是判断这个头文件是否在多个文件中被使用,如果用了多次就只定义一次。
3.指针变量和int 和string变量的区别? void * 和int * 的区别? 函数指针是最难的, 理解函数指针使用的内存模型?
指针变量就是存地址。void就是所有类型的,
4.c语言的内存模型是啥?
1.const和staitc? const 和define的区别?
const和
static` 是C语言中用于修饰标识符(变量、函数等)的关键字,它们有不同的作用和用途。
const
关键字:const
用于声明一个常量,表示该标识符的值在程序执行期间不可被修改。例如:const int MAX_VALUE = 100;
声明了一个常量MAX_VALUE
,其值为100,不能修改。const
还可以用于修饰函数的参数,表示该参数在函数内部不可被修改。这样可以确保函数不会意外修改传入的参数的值。
static
关键字:static
用于修饰全局变量时,表示该变量的作用域仅限于当前文件。这样可以防止其他文件访问该变量,实现了变量的封装性。static
用于修饰局部变量时,表示该变量在函数调用结束后仍然保持其值,不会被销毁。下次调用该函数时,变量的值仍然有效。static
还可以用于修饰函数,表示该函数的作用域仅限于当前文件,其他文件无法调用该函数。
define
宏定义:define
是C语言中用于定义宏的预处理指令。它可以用于定义常量、函数宏、条件编译等。define
定义的宏在编译前进行简单的文本替换,没有类型检查和作用域的概念。例如:#define PI 3.14159
定义了一个宏PI
,在编译时会将PI
替换为3.14159
。define
宏定义可以用于替代常量,但是它没有类型信息,也没有作用域限制,容易引发一些意外的错误。
区别:
const
是C语言中的关键字,用于声明常量或修饰函数参数的不可修改性。它具有类型信息,可以进行类型检查,作用域由变量的声明位置决定。static
是C语言中的关键字,用于修饰变量、函数的作用域和生命周期。它可以限制变量或函数的作用范围,使其在其他文件中不可见或保持值的持久性。define
是C语言中的预处理指令,用于定义宏。宏定义在编译前进行简单的文本替换,没有类型信息和作用域限制。
总结来说,const
是用于声明常量或修饰函数参数的关键字,static
是用于限制变量或函数的作用范围和生命周期的关键字,而 define
是用于定义宏的预处理指令。它们在功能和用途上有所区别。
2.volatile和extern是什么?
volatile和
extern是C语言中的两个关键字,而
const int* a = &b和
int const * a = &b` 是两个指针声明的变体,它们之间有一些区别。
volatile
关键字:volatile
用于修饰变量,表示该变量的值可能会在程序执行期间被意外地修改,从而告诉编译器不要对该变量进行优化。这通常用于与硬件相关的变量,例如表示外部设备状态的寄存器。volatile
告诉编译器不要对变量进行缓存优化、寄存器优化或重排序优化,以确保每次访问变量时都从内存中读取最新的值。
extern
关键字:extern
用于声明一个变量或函数是在其他文件中定义的,即该标识符的定义在其他文件中,当前文件只是引用该标识符。这样可以实现跨文件的变量或函数共享。extern
告诉编译器该标识符在其他地方定义,不需要在当前文件中重新定义,只需引用即可。
3. const int* a = &b和 int const * a = &b的区别
const int* a = &b
和 int const * a = &b
的区别:
- 这两个声明都定义了一个指向
int
类型的常量指针a
,指向变量b
的地址。 const int* a = &b
表示指针a
是一个指向int
类型常量的指针,即通过a
不可以修改b
的值,但可以通过其他途径修改。int const * a = &b
与上面的声明等价,也表示指针a
是一个指向int
类型常量的指针,不可以通过a
修改b
的值。- 在这两种声明中,
const
关键字修饰的是指针所指向的内容,表示指针指向的值是常量,而不是指针本身。
综上所述,volatile
用于修饰变量,表示变量可能会被意外修改;extern
用于声明变量或函数在其他文件中定义;const int* a = &b
和 int const * a = &b
都定义了常量指针,表示指针指向的值是常量,不可通过指针修改。两种声明的语法稍有不同,但含义相同。
5.C语言的内存模型
C语言的内存模型可以简单地描述为由以下几个部分组成:
- 栈(Stack):
- 栈是用于存储函数调用过程中的局部变量、函数参数以及函数调用的上下文信息的一块内存区域。
- 栈是一种后进先出(LIFO)的数据结构,函数调用时会将局部变量和函数参数压入栈中,函数返回时再将其弹出。
- 栈的大小在程序运行期间动态地增长和缩小。
- 堆(Heap):
- 堆是用于动态分配内存的一块内存区域。
- 堆中的内存可以通过函数如
malloc()
、calloc()
和realloc()
进行分配和释放。 - 堆中的内存需要手动管理,使用完毕后需要通过相应的函数进行释放,否则可能会导致内存泄漏。
- 全局变量区(Global Data):
- 全局变量区用于存储全局变量和静态变量。
- 全局变量和静态变量在程序的整个执行过程中都存在,它们的内存分配在程序启动时完成,并在程序结束时释放。
- 常量区(Constant Data):
- 常量区用于存储常量数据,例如字符串常量、全局常量等。
- 常量区的数据在程序执行过程中是不可修改的。
- 代码区(Code):
- 代码区存储程序的指令代码。
- 代码区是只读的,程序执行过程中不允许修改代码区的内容。
需要注意的是,内存模型的具体实现可能会因操作系统、编译器和硬件平台的不同而有所差异。上述描述是一种常见的内存模型,但并不代表所有情况。
6.C语言的底层原理
C语言是一种通用的高级编程语言,它可以用于开发各种应用程序,包括嵌入式系统、操作系统、驱动程序等。C语言的底层原理涉及到编译器、汇编语言和计算机硬件之间的关系。
- 编译器:C语言的源代码需要通过编译器进行编译,将其转换为机器可执行的指令。编译器会对源代码进行词法分析、语法分析和语义分析,生成相应的目标代码。
- 目标代码:编译器生成的目标代码是针对特定硬件平台的中间代码。它通常是一种低级的表示形式,包含了与硬件相关的指令和数据。
- 汇编语言:目标代码可以进一步通过汇编器转换为机器码。汇编语言是一种与机器指令一一对应的符号表示形式,它更接近于计算机硬件的操作方式。
- 机器码:机器码是计算机可以直接执行的二进制指令。它由一系列的位模式组成,每个模式代表一条特定的机器指令。机器码是计算机底层的操作语言,用于执行各种计算和操作。
- 寄存器:计算机的中央处理器(CPU)包含一组寄存器,用于存储和处理数据。寄存器是非常快速的存储器件,可以直接参与运算和数据传输。
- 内存:计算机的内存用于存储程序和数据。C语言中的变量和数组等数据结构都存储在内存中。内存被划分为不同的地址,每个地址对应一个存储单元。
- 栈和堆:C语言中的函数调用和局部变量通常使用栈来管理。栈是一种后进先出(LIFO)的数据结构,用于存储函数的调用信息和局部变量。堆是一块动态分配的内存,用于存储动态分配的数据,如通过malloc()函数分配的内存。
- I/O操作:C语言通过标准库提供了与输入输出设备的交互功能。标准库中的函数可以实现键盘输入、屏幕输出、文件读写等操作。
C语言的底层原理涉及到编译过程、汇编语言、机器码和计算机硬件等方面。了解这些原理可以帮助程序员更好地理解和优化代码,以及开发底层系统级的软件。