C语言知识深度汇总(本文仅谈语言,且不适合初学者阅读)

修正的部分内容的索引放在这里进行说明:
第一次修正:关于自定义类型那里进行了部分内容的修正
第二次修正:
1.对语句部分进行了大程度的修正
2.对数组部分进行了大程度的修正
3.补上了位段的一系列操作
4.对文章中的一些地方进行了小幅度修改(使之更严谨,更容易阅读理解)
第三次修正:
1.增加了文件操作部分的内容
2.对文章中的一些地方进行了小幅度修改。
第四次修正:
1. 对关键字部分进行了调整,这里感谢网友“gsfdjgji”在评论区指出我的错误!
2.对柔性数组部分进行了详细说明
第五次修正:
1.内存管理
2.对文章中的一些地方进行了小幅度修改


一、数据类型

我在开头这里提一下c语言标识符和关键字

c语言的标识符不能和标准库中的关键字重名,除此外,它由字母、数字、以及下划线组成,只能以字母或者下划线开头。这里两种命名方法,各举一个例子(这两种没有优劣之别,使用完全看个人习惯):

  • 驼峰命名法:StringLength

  • 下划线命名法: string_length

c89规定c语言的关键字一共有32个,我在这里讲一下typedef和volatile
  • typedef
    这个关键字常用于给类型重命名,eg:typedef char* p_char
    这就代表以后可以用p_char 来代表指向字符的指针类型了。
    它的好处有这两点:
    1、使复杂的声明变得简单,避免出错和提高代码的可阅读性
    2、可以隐藏指针,数组语法
    这里把typedef和#define做一个区别对比:
    他们两个都可以给类型名更改一个名字,但是不同于typedef的是,#define只是简单的符号替换,并没有使一个标识符根本上成为一种已知的类型名( 我这么说你可能听不明白,没关系,我写一段代码,结合我的文字你绝对就理解了 )
    1、

        define p_char char *
        p_char a,b;
    

2、

        typedef p_char char *;
        p_char a,b;

第一段代码中的a是一个指向字符的指针,而b只是一个字符变量
第二段代码中的a、b都是指向字符的指针

还有,#define重命名的类型支持扩展,而typedef重命名的类型不支持扩展,看以下代码:

#define INT int
unsigned INT a,b;//a、b均为无符号整形变量

typedef INT int
unsigned INT a,b;//错误,这就相当于是两个关键字套在一起:char int a,b
  • volatile【定义】:被这个关键字修饰的变量,当编译程序需要获取或者存储这个变量的值时,都从它的地址中来获取,而不要在某些情况下为了优化速度,从临时寄存器中获取(因为若是此时刚好别的程序通过地址更新了这个变量的值,寄存器中的那个值就会过时,从而出现错误)
    我在这里举一个例子:
#include<stdio.h>
int main()
{
    const int num=10;
    int *p=(int *)&num;
    printf("%d ",num);
    *p=20;
    printf("%d\n",num);
    return 0;
}

在c++的编译器上这个输出结果是:

10 10

但是如果把定义num的那行代码改成这种

volatile const int num=10;

那么输出结果就会是我们想要的

10 20

注:c89规定了32个关键字,c99又新增了“_Bool ”,“_Complex ”,“ _Imaginary ”,
“restrict ”,“inline ”五个关键字。

一、基本数据类型(以下描述均在32位cpu环境下)

下面的书写的格式为: 所占位数->所表示范围

  • <字符型>(char):1->(-2^7 ~ 2^7-1)

  • <整形>
    短整形(short)
    signed short: 2->(-2^15 ~2^15-1)
    unsigned short: 2->(0 ~2^16-1 )
    整形(int)
    signed int: 4->(-2^31~2^31-1)//少的那一位是符号位
    unsigned int:4-(0~2^32-1 )
    长整型(long)
    signed long: 4->(-2^31~2^31-1)
    unsigned long: 4->(0~2^32-1 )
    long long(c99新加的类型)
    signed long long: 8->( -2^63 ~ 2^63-1)
    unsigned long long: 8->(0~2^64-1)

  • <浮点型>
    单精度浮点型(float):4-> +/-3.40282e+038 (7~8位有效数字)
    双精度浮点型(double):8-> +/-1.79769e+308 (15~16位有效数字)

    下面我特地讲一下,浮点型和整形在内存中的存储方式

1>整形

这里我们要知道什么是原码、反码和补码:
1)原码:将一个整数转换成二进制形式就是它的原码(即正数和负数的原码相同)
2)反码:负整数的反码就是它的原码除首位的符号位外其他位按位取反,正数的反码就是它的原码
3)补码:负整数的补码就是它的反码加一,正整数的补码就是它的原码

一切整数在内存中都是以它的补码的形式存储的,而读取的时候则转换回原码。这样的存储方式有两个好处
- 简化了硬件电路
- 把加法和减法合并为一种运算

2>浮点型数据在内存中的存储方式

对于32位的浮点数来说(float):最高的一个bit位(示意图如下)是符号位,用1来表示负数,用0来表示正数。接下来的8个bit位用来表示指数,剩下来的23位均用来表示数值。

这里写图片描述

对于64位的浮点数来说(double),大体和32位相同

这里写图片描述

指数位的存储规则

比方说数字12.125,它首先会转换成二进制的数字:1100.001。用指数表示法就是1.100001 x 2^3,又因为所有的数字转换成二进制指数表示法小数点前的数都是1,所以这个数字和小数点就都可以省略了(若是0.1xx怎么办?当然是转换成1.xxx *2^-xx的形式了。。。),然后将截取后的尾数放到尾数位,不满的则补0。指数位置的存储方式是取能表示的数的范围中的中间值(8位范围为0~255,所以中间值就是127),然后给2的指数减去这个数字(读取的时候再加上),然后转换成二进制的形式,然后放到指数的位置。

二、自定义数据类型

struct定义的结构体类型、union定义的联合体(共用体)类型、enum定义的枚举类型

这里提一下关键字typedef,typedef的用法就是给原有的数据类型起一个名字,方便以后的使用。例如:
typedef struct Node
{
int _data;
struct SList *_next;
}Node;
以后再用到上面封装的那个结构体类型时,就不用使用struct Node来定义了,直接用Node来定义可以了,这样一方面时为了减少因为手误而出现的错误,一方面也可以使代码变得简洁。

二、基本语句

1、判断语句
  • if……else
    这里有一个易错的问题:”悬空else”,下面举一个例子说明:下面这段代码给我们由于缩进的原因给我们的直观感觉就是第一个if和下面的else对应为一对,但是实际上是第二个if和else相对应,因为else总是和上面紧接着的if相对应,但是这里的错误往往不易察觉!最有效的避免这种错误的一个方法就是给每一个if和else后面都加上花括号,将要要执行的代码括起来,这样即使出现缩进错误,也不会再出现上面的问题。
if(judge)
    if(judge)
      code block1;
else
    code block2;
/*下面是修改后的代码,当然也不推荐这样子写,缩进最好还是要按照一定的
  原则对齐,下面只是起到一个对照的作用*/
if(judge){
    if(judge){
        code block1;
    }
else{
    code block2;
    }
}
  • switch……case
    这里我强调一下,最好不要用default来表示最后一种情况,否则你既丧失了case语句的自说明功能,又失去了default语句处理意外事件的功能。
  • 25
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值