C语言总结

1.C语言程序运行的内存结构:栈,堆,BBS,数据段,代码段
在这里插入图片描述

BBS:未初始化的全局变量、全局静态变量(静态内存分配)
数据段:已初始化的全局变量,全局静态变量,局部静态变量,常量数据
代码段:可执行代码,字符串常量
堆:用于存放进程运行中被动态分配的内存段
栈:用户存放程序临时创建的局部变量,也就是函数括弧”{}”中定义的变量,此外,在函数被调用时,其参数也会被压入到栈中,并等到调用结束后,函数的返回值也会被存放回栈中。
栈中存放函数内部的变量,参数,返回地址

2.GCC的编译过程:
预处理:头文件包含,宏替换,条件编译,删除注释
编译:主要进行词法,语法,语义分析等,检查无误后将预处理好的文件编译成汇编文件
汇编:将汇编文件转换成二进制文件
连接:将项目中的二进制文件所需的库和启动代码连接成可执行文件

3.Static
全局变量存储在静态存储区中,局部变量在堆栈中
静态局部变量:和不同变量不同。静态局部变量也是定义在函数内部的。静态局部变量所在的函数在调用多次时,只有第一次经历变量定义和初始化,以后多次调用不再定义和初始化。
静态全局变量:只初始化一次,但是作用域在当前文件和模块中。每次调用当前文件时,会使用上一次保存的值。
静态函数:只在本模块或者文件中使用。被限定了范围。
各种指针
在修饰变量时,static修饰的静态局部变量只执行一次,而且延长了局部变量的生命周期,知道程序运行结束以后才能释放。
Static修饰的全局变量,只能在本文件中访问,不能在其他文件中访问,即便是extern外部声明也不可以。
Static修饰一个函数时,这个函数只能在本文件中调用,不能被其他文件调用。Static修饰的局部变量存放在全局数据区的静态变量区,初始化的时候自动初始化为0。
(1)如果不想被释放的时候,可以使用static修饰。比如:修饰函数总存放在栈空间的函数。如果不想让这个数组在函数调用结束时释放,可以是哦刚static修饰。
(2)考虑到数据安全性,当程序想要使用全局变量的时候,应该先考虑使用static

4.各种指针
NULL指针:用于指示指针未指向有效位置
悬空指针:没有指向正确内存位置的指针。当删除或释放对象时,如果不修改指针的值或者不置为NULL,就会出现悬空指针。
野指针:只声明没有初始化过的指针。

5.#与##的作用:
在这里插入图片描述

6.作用域:程序中该标识符可以被使用的区域
文件作用域:任何所有代码块之外声明的标识符都具有文件作用域
函数作用域:只适用于语句标签(goto)
代码块作用域:任何在代码块的开始位置声明的标识符都具有代码块作用域
原型作用域:只适用于在函数原型中声明的函数名

7.参数传递方式
值传递(void swap(int a)):把实参的值复制一份,实参和形参拥有不同的存储单元。形参开辟内存空间,实参与形参的地址不同,不能改变值。
地址/指针传递(void swap(int *p1,int *p2)):实参和形参拥有同一块内存空间。形参开辟内存空间,实参与形参的地址想通,能改变值。
引用传递(void swap(int &a,int &b)):地址传递和引用传递都是按传递变量所在的地址,函数的主要作用就是对存储在地址中的变量进行直接的操作。形参开辟内存空间,实参与形参的地址相同,能改变值。
按值传递则不会修改原值,指针传递也是值传递,他传递的是指针变量的值,引用传递相当于间接寻址,他直接传递的是地址。

8.内联函数与宏的区别:
1.内联函数在编译时展开,宏在处理时展开。
2.内联函数直接嵌入到目标代码中,宏是简单的做文件替换。
3.内联函数有类型检测,语法判断等功能,而宏没有。
4.inline函数是函数,而宏不是。

typedef和define的区别:
1.typedef仅限于为类型定义符号名称,定义一种类型的别名,而不只是简单的宏替换,define不仅可以为类型定义别名,也能为数值定义别名。
2.Typedef编译阶段会检查错误,define预处理阶段不检查错误

9.Const与宏的区别:
1.数据类型:const修饰的变量有明确的类型,而宏没有明确的类型。
2.安全方面:cons修饰的变量会被编译器检查,而宏没有安全检查。
3.内存分配:cons修饰的变量只会在第一次赋值时分配内存,而宏是直接替换,每次替换后的变量都会分配 内存。
4.作用场所:const修饰的变量作用在编译,运行过程中,而宏作用在预编译中。

10.数组名作为类型,作为地址,对数组名取地址的区别?
1.数据名作为类型:代表的是整个数组的大小。
2.数组名作为地址:代表的是数组首元素的地址。
3.对数组名取地址:代表的是数组的首地址。

11.字节对齐规则:
1.前面的地址必须是后面的地址的整数倍,不是就补齐。
2.整个struct的地址必须是最大最大字节的整数倍。
int 4,double 8,char 1,占用字节为24。Int 4 ,char 1,double 8这样就是16个字节,省了内存。

12.violate关键字:
violate是一个类型修饰符,防止编译器对代码进行优化。在编译期间,编译器可能对代码进行优化。当编译器看到此处的n被const修饰。从语义上讲,n是不期望被修改的,所以优化的时候把n的值存放到寄存器中,以提高访问的效率。
只要以后使用n的地方都在寄存器中取,即使n在内存中的值发生变化,寄存器也不受影响,所以,输出的n的值为0,也就是其他线程可能读到的值是修改之前的值。
使用violate修饰之后,就不会将辞职拷贝到寄存器中,那么其他线程可以读到修改之后的值,也就是可见性。Violate的作用即使被设计用来修饰不同线程访问和修改的变量的

13.Attribute:主要是用来在函数或数据声明中设置其属性,与编译器相关,可以设置多种属性。

14.数组的特点:
1.同一个数组所有的成员都是相同的数据类型,同时所有的成员在内存中的地址是连续的
2.不初始化:如果是局部数组,数组的内容随机,如果是全局数组,数组的元素内容自动赋值为0.
3.完全初始化:如果一个数组全部初始化,可以省略元素的个数,数组的大小按初始化的个数确定。

15.Const:意味着只读,当值被修饰的变量的内容内修改。(修饰常量,修饰函数形参,修饰函数返回值)
1.在函数声明时,修饰参数表示在函数调用时参数(包括指针和实参)的值不会发生改变。
2.对于指针而言,可以指定指针本身为const,也可以指定指针所指的数据为const,const修饰的都是后面的值。

15.C函数调用过程:
1.根据调用的函数名找到函数入口。
2.在栈中申请调用函数中的参数及函数体内定义的变量的内存空间。
3.函数执行完后,释放栈中申请的参数和变量的空间,最后返回值。

16.指针常量与常量指针
1.指针常量(int *const p):指针的值不能修改,指针指向的值可以修改。
2.常量指针(int const *p):指针可以修改,指针指向的值不能修改。
3.const int *p:都不能修改。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Serendipity_ry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值