• C语言-基础


    参考

    https://www.runoob.com/cprogramming/c-tutorial.html

    gcc

    编译与链接

    编译:通过编译器,识别源文件中的语句,将其转换成计算机能够识别的二进制形式

    编译后,生成的是目标文件,不是最终的可执行文件
    目标文件(中间文件),是二进制形式(.o.obj

    链接:通过链接器,链接生成可执行文件。编译只是对自己编写的源文件进行编译,链接是将源文件的目标文件和标准库、动态链接库等结合起来,组成最红的可执行文件
    即,将所有二进制形式的目标文件和系统组件组合成一个可执行文件

    嵌入式编译器:CCS (DSP)

    多文件编译

    gcc test.c test2.c -o main.out
    file.out 是可执行文件

    头文件/库文件

    头文件

    头文件包含若干函数
    使用外部函数,要引入对应的头文件
    通常,头文件只包含函数的说明,即函数怎么用;而函数本身保存在其他文件,在链接时会找到
    #include#include的作用就是将头文件中的文本赋值到当前文件,然后一起被编译器编译

    库文件

    区别

    变量

    对于不带初始化的定义:带有静态存储持续时间的变量会被隐式初始化为NULL(所有字节的值都是0),其他所有变量的初始值是未定义的
    需要建立存储空间的变量变量在声明的时候就已经建立了存储空间
    无需建立存储空间:通过extern关键字声明变量名,而不定义他,这种可以在别的文件中定义

    变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储
    声明与定义???
    extern int i 是声明,不是定义
    int a 是声明,也是定义

    左值/右值???

    左值:指向内存位置的表达式, 叫做左值表达式
    右值:内存中某些地址的数值

    字面量/常量

    字面量:常量 – 不允许进行修改
    整型常量、浮点常量、字符常量、字符字面值、枚举常量、定义常量

    定义常量

    • #define 预处理器
    • const 关键字
    // #define
    #define Variable value // 注意没有分号 可以定义字符型、字符串型的常量
    
    // const
    const type variable=value; // 注意有分号,且必须直接赋值
    
    • 1
    • 2
    • 3
    • 4
    • 5

    变量作用域

    • 在函数或块内部的局部变量

    在某个函数或块内部声明的变量称为局部变量,只能被函数或该代码块内部的语句使用

    • 在所有函数外部的全局变量

    全局变量在整个声明周期内都是有效的,在任意的函数内部都能访问全局变量

    • 形参

    被当做函数内的局部变量

    命名冲突

    局部作用域内,优先使用局部变量

    全局变量与局部变量

    全局变量:保存在内存的全局存储区中,占用静态的存储单元
    局部变量:保存在栈中,只有在所在函数被调用时才动态的为变量分配存储单元

    初始化局部变量和全局变量

    局部变量被定义时,系统不会对其初始化(或随机初始化,根据编译器的不同策略不同),必须手动对其初始化
    全局变量被定义时,系统会自动对其初始化,默认是0,(因为全局变量存储在内存分区中的全局数据区,这个区域中的数据在程序载入内存后会初始化为0)

    int 0char-\0float 0double 0pointer NULL

    未初始化的变量会导致一些在内存位置中已经可用的垃圾值

    作用域扩展 python

    a=1
    b=2
    c=4
    def f():
        print(c)
        c=a+b
    f()
    print(c)
    # c为局部变量,会报错!!!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    存储类

    存储类:定义c程序中变量/函数的范围(可见性)和声明周期
    说明符,放在所修饰类型的类型之前

    • auto
    • register
    • static
    • extern

    auto

    所有局部变量的存储类,只修饰局部变量,只用在函数内

    int func()
    {
    	// 下面两种写法都表示的是局部变量
    	int mount;
    	auto int month;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    register

    定义存储在寄存器中而不是RAM中的局部变量,意味着变量的最大只存等于寄存器的大小(一个字节),且不能也对它应用一元运算符???
    寄存器只用于需要快速访问的变量,如计数器等(定义了register,并不意味着变量将被存储在寄存器中,只是意味着变量可能存储在寄存器中,这取决于硬件和实现的限制)

    int func()
    {
    	register int miles;
    }
    
    • 1
    • 2
    • 3
    • 4

    static

    https://www.runoob.com/w3cnote/cpp-static-usage.html – 还没看

    指示 编译器 在 程序 的生命周期内 保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁,因此使用static修饰局部变量可以在函数调用之间保持局部变量的值
    static也可以修饰全局变量,当修饰全局变量的时候,会是变量的作用域限制在声明它的文件中。全局声明的一个static变量或方法可以被任何函数或方法调用,只是必须与被修改的变量或方法在同一个文件中

    int func()
    {
    	// num 是局部变量,但是只被初始化一次,每次调用函数func的时候,num不会被重置
    	static int num=10
    	num--;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    extern

    提供一个全局变量的引用,全局变量对所有程序文件都是可见的
    使用extern无法初始化变量,会把变量名指向一个之前定义过的存储位置
    其实就是 A文件中定义了一个可以在B文件中使用的全局变量或函数,那么在B文件中就可以使用extern来得到A文件中定义的变量或函数的引用(用在在另一个文件中声明一个全局变量或函数)
    进阶:A/B文件可以存在相互的使用extern

    // A.c
    #include 
    int count;
    extern void write_extern();
    
    int main()
    {
    	count=5;
    	write_extern();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    // B.c
    #include 
    extern int count;
    void write_extern(void)
    {
    	printf("count is %d\n",count)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    数据类型

    • 基本类型
    • 枚举类型

    只能被赋值一定的离散整数值变量

    • void类型

    类型说明符,表明没有可用的值

    • 派生类型

    指针类型、数组类型、结构类型、共用体类型和函数类型
    其中:函数类型指的是函数返回值的类型

    基本类型

    整数类型

    • char

    1个字节,[-128,127] 或[0,255]

    • unsigned char

    1个字节,[0,255]

    • int

    2或4字节,(win 4字节)

    • unsigned int

    2或4字节

    • short/unsigned short

    2字节

    • long/unsigned long

    4字节

    • double

    8字节

    前缀:表示进制关系
    后缀:表示有符号(默认)和无符号整型U、长整型L,大小写任意,顺序任意

    有符号和无符号

    当以有符号数的形式输出时,printf会读取数字所占用的内存,并把最高位作为符号位,把剩下的内存作为数值位,但是对于有符号的正数而言,最高位恰好是0,所以可以按照无符号数的形式读取,且不会有任何的数值影响
    当以无符号的形式输出时,printf也会读取数字所占用的内存,并把所有的内存都作为数值位对待

    进制数

    0b 0B # 二进制数 
    0x 0X # 十六进制数
    0 #八进制
    
    • 1
    • 2
    • 3

    注意标准编译器不支持0b的二进制写法,只是某些编译器在扩展后支持
    注意printf 输出形式

    整型只控制字节长度,和数值范围
    进制数才是实际数值的表现形式
    一个数字不管以何种进制来表示,都可以 以任意进制的形式输出,因为数字在内存中始终以二进制的形式存储
    其他进制的数字在存储前都必须转换成二进制形式,而在输出前也需要反转

    原码/补码/反码

    原码:数值的二进制数,包括符号位
    反码:

    正数的反码=原码
    负数的犯法=符号位不动,其他位置取反

    补码:

    正数的补码=原码
    负数的补码:是反码加1

    -128的补码就是1000 0000
    补码 1000 0000 就表示-128 记录就可以了
    深究里边,是因为符号位会被数值的高位进行多次覆盖

    计算机内存中,整型一律采用补码的形式存储,因此读取整数时还要采取逆向的转换,也就是将补码转换为原码

    数值溢出

    浮点类型

    • float

    4字节,32位

    • double

    8字节,64位
    对于小数默认是double类型

    • long double

    16字节

    float x=1.2 # 赋值的时候,会先从double类型转换为float类型
    
    # 后缀
    float x=1.2f # 赋值的时候直接是默认的float类型
    
    • 1
    • 2
    • 3
    • 4

    注意所有的浮点型都是以双精度double进行运算的,即使是float类型,也要先转换成double类型

    定义了宏,可以在程序中使用这些值和其他有关实数二进制表示是的细节

    #include 
    
    FLT_MIN # 最大值
    FLT_MAX # 最小值
    FLT_DIG # 精度值
    
    • 1
    • 2
    • 3
    • 4
    • 5

    字符型

    单引号
    charunsigned char 是一个字符类型,用来存放字符,但是同时也是一个整数类型,也可以用来存放整数!!!,注意取值范围
    char 1个字节,[-128,127]
    unsigned char 1个字节,[0,255]
    char 类型只能存储ASCII字符,不能存储其他字符根据上面的定义,也可以存放范围以内的进制数

    字符与整数

    由于char类型只能存储ASCII字符,字符集及其编码其实本质上就是二进制数,(本质上与整型没有区别)
    定义一个char类型字符,会先转换成ASCII字符对应的编码再存储
    而存储一个整型的时候,不需要任何转换直接存储
    由于数据类型不同,所以需要的字节位数不同,因此在存储和读取的时候占用的内存不一样,所以在读取 字符型和整型 的时候并不会有冲突

    字符与进制数/字符型进制数

    字符型与进制数

    由于char可以存放整型,所以可以声明和定义取值范围内的进制数
    下面的例子中,就可以把char想象成整型(但是要注意取值范围)

    char a=0x32 # 
    printf("%c",a) // 2
    printf("%d",a) // 50 这是因为由十六进制转换为的十进制 
    
    // 与python类别
    // '2'.encode().hex() # 32
    // int('32',16) # 50
    // chr(50) # '2'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    对于char类型的字符,(由于是窄字符,且只占一个字节,所以可以使用ASCII编码),(又由于ASCII编码的结果就是一个二进制数),可以利用转义的进制数进行表示
    下面的例子,就可以把其当成字节对象(字节串对象),想当于python中的bytes对象,

    char a='\x31' // a是字符数值1
    char b='\x61' // b是字符a
    
    char *str1="\x31\x32\x33\x61\x62\x63" // 字符串"123abc"
    
    // 类别python
    // '123abc'.encode().hex() # '313233616263'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    putchar

    输出字符的专用函数

    转义字符

    printf("\"string\'") // "string'
    
    • 1

    中文字符

    对于中文字符应该使用宽字符的形式,并加上前缀,加上前缀后,所有的字符都变成了宽字符的存储形式
    wchar_t类型,在不同的编译器下对不同的语言使用不同的长度

    #include 
    wchar_t a=L'中'
    
    • 1
    • 2
    宽/窄字符(串)

    char类型的窄字符,使用ASCII编码
    char类型的窄字符串,通常来讲是UTF8编码,(其实不同的编译器在不同的平台上编码方式不同)
    wchar_t类型的宽字符或宽字符串,使用UTF16或32编码

    见文档

    字符串型

    双引号
    在内存中占一块连续的内存
    其实字符串数据,依靠的是数组和指针来简介的存储字符串

    char s1[]="string1";
    char *s2="string2"
    
    • 1
    • 2

    puts

    专门用于输出字符串数据

    sizeof

    获得当前平台上的对象或类型的存储字节大小

    printf("%lu",sizeof(int))
    printf("%d",sizeof(instance))
    
    • 1
    • 2

    数据类型转换

    数据类型存在强制转换
    原则

    浮点数赋给整型:浮点数小数部分会被舍去(注意不是四舍五入)
    整数赋值给浮点数,数值不变,但是会被存储到相应的浮点型变量中

    在这里插入图片描述

    强制转换

    注意,强制转换是临时性的,并不会影响数值本身的数据类型和值

    (类型说明符)(表达式)
    (int)(x+y)
    
    • 1
    • 2

    基本运算

    ±*/

    下面的例子中 由于都是int类型,所以即使是算出了float值,也会变成int类型,只不过在printf变成了对应的格式
    因此必须在先前就想结果类型

    int a=1;
    int b=2;
    float c;
    c=a/b;
    printf("%f",c); // 0.000000
    
    • 1
    • 2
    • 3
    • 4
    • 5

    / %

    %取余运算,只能作用于整型,不能作用于浮点型

    注意:正负数,只根据%左边的数值符号决定!!!

    ++/- -

    • ++ 自增
    • -- 自减
    num++; // 先运算后+1
    num--; // 先运算后+1
    
    //例子
    v=num++; // v=num;num+=1
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ++num/num++

    num++; // 先运算后+1
    ++num; // 先+1后运算
    
    • 1
    • 2

    逻辑运算

    • &&and
    • ||or
    • !not

    位运算

    • &
    • |
    • ^ 异或
    • ~ 取反
    • << 左移
    • >> 右移

    ? :

    如果条件为真?则值为x:否则值为y

    运算优先级

    注意结合性

    void 类型

    函数返回为空
    函数参数为空,不接受任何参数,int main(void)
    指针指向void:类型为void*的指针 代表对象的地址,而不是类型

    printf

    https://www.runoob.com/cprogramming/c-function-printf.html – 没看完
    http://c.biancheng.net/view/1793.html?from=pdf_website_1_0 – 没看

    %

    %d //十进制有符号整数
    %u //十进制无符号整数
    %f //float浮点数,默认保留六位小数,不足六位以0补齐,超过六位按四舍五入阶段
    %lf //double
    %c //字符
    %s //字符串
    %p //指针的值
    %e //指数形式的值
    %x //十六进制 无符号
    
    %lu //32位无符号整数
    ...
    
    // printf的高级写法,用于区分不同的进制数字
    print("a=%#hx",0x1d)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    整型、短整型、长整型,分别有对应的printf输出形式
    printf中不能输出二进制数
    需要某些转换函数

    一个数字不管以何种进制来表示,都可以 以任意进制的形式输出,因为数字在内存中始终以二进制的形式存储
    其他进制的数字在存储前都必须转换成二进制形式,而在输出前也需要反转

    在这里插入图片描述

    注意事项

    有符号和无符号
    当以有符号数的形式输出时,printf会读取数字所占用的内存,并把最高位作为符号位,把剩下的内存作为数值位,但是对于有符号的正数而言,最高位恰好是0,所以可以按照无符号数的形式读取,且不会有任何的数值影响
    当以无符号的形式输出时,printf也会读取数字所占用的内存,并把所有的内存都作为数值位对待
    因为通过格式控制符进行数值输出的时候,其实并不会检查定义的数值是有符号还是无符号数,只会按照格式控制符对数值进行特定的解释

    转义字符与特殊字符

    "\\"%%

    scanf

    从控制台读取数据

    控制方法

    if-else

    if (condition)
    {
    	...
    }
    else if (condition)
    {
    	...
    }
    else ()
    {
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    switch-case

    switch-expression 必须是一个常量表达式,一个整型或一个枚举类型
    expression1/2 必须是与expression类型相同的数据,且必须是常量或字面量
    如果case不加break,控制流会继续后面的case,直到遇到break
    当所有的case都不匹配的时候,有一个可选语句default,default语句中的break不是必须的

    swtich(expression)
    {
    	case expression1:
    		...
    		break;
    	case expression2:
    		...
    		break;
    	default:
    		...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    while

    while(condition)
    {
    	...
    }
    
    • 1
    • 2
    • 3
    • 4

    for

    int会首先被执行一次,且只会被执行一次;这一步可以声明并初始化任何循环控制变量,也可以不写任何语句,只有一个分号即可
    然后会判断condition,如果为真则执行循环主体,如果为假,则不执行循环主体,且控制流会跳转到紧接着for循环的下一条语句
    执行完for循环主体后,控制流会跳回increment,该语句可以留空,只要在条件后有一个分号出现即可
    条件再次被判断,如果为真,则执行循环,条件变为假的时候,for循环终止

    for(int;condition;increment)
    {
    	...;
    }
    
    • 1
    • 2
    • 3
    • 4

    do-while

    函数体至少会被执行一次

    do
    {
    	...;
    }while(codition);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    AI 模型社区“魔搭”亮相,平头哥又上新,端云一体生态再升级
    Java校招120道面试题目合集
    从0-1,使用腾讯OCR进行身份证识别
    SpringCloud(6):feign详解
    谷粒学苑_第九天
    设计模式--适配器模式
    短信的信令过程
    C++ Primer 第4章 表达式
    2.类与对象 拜访对象村
    OELD透明拼接屏,在朝阳市市场蓬勃发展,助力商业展示效果升级
  • 原文地址:https://blog.csdn.net/L_fengzifei/article/details/126279569