C语言复习

本文详细介绍了C语言中的核心知识点,包括数据类型、运算符、数组、函数、结构体、指针、文件操作、编译预处理、位运算和内存管理。重点讲解了指针的多种应用,如数组指针、指针数组、二级指针以及函数指针。此外,还涵盖了文件操作的函数,预处理指令,位运算的应用,以及内存管理中的动态内存分配和释放。文章深入浅出,适合C语言的学习和复习。
摘要由CSDN通过智能技术生成

C语言复习

整体框架

数据类型,运算符和表达式
1:进制转换
2:常量(重点)
3:变量
4:类型转换(重点)
5:运算符与表达式
数组
1:一维数组
2:二维数组(重点)
3:指针和一维数组
4:字符数组和字符指针(重点) 
函数
1:定义与声明
2:实参,形参,返回值
3:嵌套调用
4:递归调用(重难点)
5:数组作为函数参数
6:局部变量和全局变量(理解内存管理)
7:内部函数,外部函数,多文件编译(重点了解原理,源文件编译过程)
结构体
1:结构体指针和数组
2:typedef(重点,常用)
3:结构体的嵌套(常用)
4:内存字节对齐(重点理解)
5:联合体(共用体union)
6:枚举(enum) 
7:内存动态申请与释放(重点)
8:链表基础(链表相关的函数,头插,尾插,删除结点,数据结构中常用)
指针(核心)
1:指针类型变量
2:指针基本运算(细节)
3:指针作为函数参数
4:指针作为返回值
5:数组指针(与指针数组区分开)
6:二维数组作为函数参数
7:指针数组
8:指向函数的指针
9:函数指针
文件操作
1:文件分类
2:文件基本操作(熟悉)
3:C标准库的I/O缓冲区(理解)
编译预处理
1:宏定义(重点)
2:条件编译(调试代码,头文件)
3:文件包含
位运算
1:位运算符(逻辑运算,移位运算,单片机控制)
2:位域
内存管理(核心)
1:动态内存分配
2:内存管理
3:const常量关键词
4:大小端(会使用简单代码测试)

数据类型,运算符和表达式

小贴士:

void(空类型)真正发挥作用的地方有三点
1:对返回值的限定
2:对函数参数的限定
3:在动态内存申请中,void* 可以为任意类型变量申请内存,然后可通过强制类型转换使其指向特定类型。

常量

整型常量

八进制表示方法:以’0’开头的数字序列,如0123,表示十进制的83
十六进制表示方法:以’0x’或’0X’开头的序列,0-9,a(A)-f(F),如0x2A表示十进制的32+10=42

字符常量:

用一对单引号括起来表示一个字符,用双引号括起来的0个或多个字符是字符串
一般的英文字母和符号都对应Ascil码,可以和数值一样参与运算,如’A’+1 = ‘B’

转义字符:表示无法输入的字符或不可见的字符
 '\n'(换行)
 '\r'(回车)
 '\t'(制表符)
 '\\'(表示'\')
 '\''(表示单引号)
 '\"'(表示双引号)
 '\b'(退格)
 \xxx :(1到3位)八进制表示法,如\101表示十进制的65,即'A'
 \xhh:(1到2位)十六进制表示法,如\x41表示十进制的65
define

命令的灵活使用,不仅可大大方便修改代码,而且程序可读性更强,使得常量有更加具体的含义,避免出现意义不清的“幻数”

变量

有符号整型数据在内存中以补码形式存放
原码:第一位表示符号位,其余位为绝对值
反码:正数的反码是其本身,负数的反码是符号位不变,其余位取反
补码:正数的补码是其本身,负数的补码是反码加1

为什么采用补码方式存放?
使用了最高位表示数据的符号位,在计算的时候,这位是不能参与数值运算的。采用补码的方式,可以让计算机”忽略”符号位,让符号位也直接参与运算。

浮点型数据在内存中以指数形式存储
float f = 3.1415926 = 0.31415926*10(1)
究竟用多少位来表示小数部分,多少位用来表示指数部分,C标准并无具体规定,由各编译器自定。底数部分越多,则精度越高,指数部分越多,则能表示的范围越大。

小贴士:

C语言中,浮点数只可比较范围大小,不可以进行相等判断。

C语言中char型本质上就是整型
1:字符型数据可以以“字符形式”或者“整数形式”输出
2:允许对字符数据进行算术运算

如何通过一个程序判断当前编译器中char代表有符号数还是无符号数?

#include <stdio.h>
int main()
{
    char c = 128;
    printf("%d\n",c);
}

输出结果为 -128,所以,当前gcc编译器char代表有符号数,最高位是标志位

类型转换

如果一个运算符两侧的数据类型不同,则计算机会自动进行类型转换,把两个操作数转换为同一类型。
1:隐式类型转换会把“较低”的类型提升为“较高”的类型
2:当自动转换无法达到目的时,可以使用强制类型转换

小贴士:

强制转换类型得到的是一个所需类型的临时变量原表达式类型并不发生变化。例如,a 原定为 float 型,则(double) a只是将变量 a 的值转换成一个double型的中间量,a的数据类型并未转换成double型。

运算符与表达式

重点:运算符优先级和结合方向

 1:二元算术运算符包括:+、‐、*、/、% 
 2:整数的除法会截断结果中的小数部分;%不能用于浮点型。
 3:'+'  '‐' 具有相同的优先级,比 * 、/、%的优先级低,相同优先级时按照从左到右的结合规则。 
 4:'-' 可以作为一元运算符,表示对数据进行取反,此时它的优先级比 *、/,% 要高。 a = a*-­b;先计算 -b,后计算乘法。 
 5:条件运算符是唯一的三目运算符,其结合方向是从右至左,(下方测试代码)其优先级较低,仅高于赋值运算符。
 6:逗号运算符是优先级最低的运算符。

#include <stdio.h>
int main()
{
    int a = 3;
    int b = 30;
    int c;
    a>5?(c = 6):b>20?(c = 8):(c = 9);
    printf("%d\n",c);
}

输出结果为:c = 8,即先执行右边的条件运算符,再执行左边的条件运算符。

数组

数组定义和使用

1:定义数组后,只能引用单个元素,不能引用整个数组
2:C89不允许对数组长度做动态定义(VC6.0),C99允许(GCC)
3:初始化时,若对全部元素赋值,则可省略数组长度如果只对部分元素初始化,长度就一定不能省略。为了程序的可读性,最好不要省略数组长度。
4:未初始化的数组,系统自动赋初值为0。

二维数组初始化

1:分行初始化

int a[3][3]={
  {1,2,3},{4,5,6},{7,8,9}};

2:顺序初始化

int a[3][3]={1,2,3,4,5,6,7,8,9};

3:省略行长度

int a[][3]={1,2,3,4,5,6,7,8,9}; 

4:部分元素初始化

int a[3][3]={
  {2},{5,6},{45,20,9}};

指针和一维数组

只有两种情况数组名不代表指向数组首元素的指针,而表示整个数组。
1:sizeof(b) 得到的是整个数组的长度
2:&b 代表指向数组的指针

小贴士:

&b+1指向的是数组最后一个元素的后一个元素(显然已越界),而&b[ 0 ]+1 指向的是b[ 1 ],因此二者虽然都代表数组首地址,但在偏移量上有本质差别。

数组名:为左值与右值的区别
1: 数组名作为右值时,转化为指向数组首元素的指针

    int a[10];
    int *pa = a + 1;
    a++;  //错,数组名不能作为左值使用
    pa++; //正确

即此时pa指向a[ 1 ]

2:左值必须是可以修改的,并且可以取到它的地址
3:数组名不能作为左值使用。

指针与数组的区别

    int a[10];
    int *pa;

相同点:
数组名a可以看作指针使用,两者都可以进行下标操作和解引用操作。

不同点:
数组:数组名a代表指针常量,指向数组首元素,但并没有给这个指针常量分配内存。即内存未分配,指向确定

指针:定义时只是给指针变量pa分配了四个字节的内存,但是没有被初始化为指向任何地址,即分配了内存,指向未定

小贴士:

指针变量未定指向,不能使用 * 运算符。

    int *pa;
    *pa = 10; //此时pa为野指针,指向不确定

字符指针与字符数组

    char str[] = "i love you";//字符数组初始化
    char *pt = "i love you";  //字符指针初始化
    str[1] = 'b';  //正确,对元素重新赋值
    pt[1] = 'b';   //错误,不能修改常量区的内容
字符数组的输入和输出

可采用“%s”格式符对字符数组和字符指针指向的字符串进行输入和输出。
1:”%s”格式输出时,遇‘\0’结束,且输出字符中不包含‘\0’。
2:“%s”格式输出时,即使数组长度大于字符串长度,遇‘\0’也结束。
3:输入时,遇空白字符(空格、制表符、回车键)结束,但获得的字符中不包含空白字符本身,而是在字符串末尾添’\0’。因此,定义的字符数组必须有足够的长度,以容纳所输入的字符。

sizeof()与strlen()
    char str[] = "hello";
    printf("%d",sizeof(str));   //结果为6,包含末尾的'\0'
    printf("%d",strlen(str));   //结果为5,字符串长度,不包含'\0'

1:sizeof()是运算符,而strlen()是函数,因此前者的对象是所有数据类型,而后者只能是字符数组。
2:前者返回对象所占内存的字节数,后者返回字符串长度。

函数

函数声明

函数在定义前,在某处需要调用,则需先声明函数,一般函数的声明会放在头文件中。

函数形参与实参

1:在函数未被调用时,不给形参分配内存单元,当函数调用时,形参才会被分配内存单元。调用结束,形参内存单元被释放。
2. 当函数调用时,形参变量被创建,用实参的值给其初始化。
3. 形参实参分配不同的内存。二者在内存中的存储位置不同。

    void test(int a)  //a为实参,调用前未分配内存,调用后,通过实参b的值对其初始化
    {
        a++;
    }                 //函数结束后,a的内存释放,但b的值未发生变化
    int main()
    {
        int b;
        test(b);
    }
函数返回值

1:函数的返回值通过return语句获得。
2. 函数可以无返回值或者有一个返回值如果要返回多个值,显然return做不到,只能通过指针或者定义全局变量完成
3. 不要省略返回值的类型,对于无返回值的函数,应该定义函数为void类型。
4. 在定义函数类型时应该和return语句中表达式类型一致,若不一致,则以函数类型为准。
5. 注意!return语句会使当前函数立即结束运行,这点在判断语句中使用最多。

指针类型函数返回值

1:指针作为返回值时也是会产生一个临时指针变量,用return后面的指针表达式来进行初始化。
2: 不要返回指向栈内存的指针

    int func(void)
    {
        int a = 5;
        return &a;            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值