第一周总结02

C语言是一种面向过程的编程语言,适合操作系统开发和硬件编程。它包括整型、浮点型、字符型等数据类型,以及变量和常量的概念。编译过程涉及预处理、编译、汇编和链接四个步骤。C语言的代码通过预处理器处理头文件,然后编译成汇编语言,再转换为机器代码。文章还介绍了C语言的变量、常量、运算符、循环和分支语句等基本概念。
摘要由CSDN通过智能技术生成

C语言介绍


C语言诞生于1971~1973年,美国贝尔实验室,肯.汤姆逊和丹尼斯.里奇(C语言之父)

C语言是专门为了编写操作系统而诞生的语言,天生适合对硬件编程,以运行速度快而著称,而且C语言非常适合编写数据结构和算法

C语言出现时间过早,所以有很多缺陷,因为没有想到普通人也可以编程,但是很多前辈总结了避免这些缺陷或陷阱的经验

建议学习书籍:《C语言三剑客》->《C陷阱与缺陷》 《C与指针》《C程序设计语言》

C语言的语法非常自由,自由源于自律,自由意味着危险

C89语法标准,旧的系统中默认的标准

C99语法标准,对C语言的扩展和增强 -std=gnu99

C11语法标准,全新的升级

C语言的第一个程序:

//导入头文件
#include <stdio.h>
//程序员所编写的代码,不是真正的标准C代码,需要一段程序翻译成标准C代码,负责翻译的程序叫做预处理器,翻译的过程叫做预处理,被翻译的语句叫做预处理指令,以#开头的语句都是预处理指令
// #include 的功能是把一个头文件导入(拷贝)到当前位置

//#include <xxx.h>:从系统指定的路径下查找并加载头文件
//#include "xxx.h":先从当前工作路径查找,如果找不到再从系统指定的路径查找并加载

//头文件:以.h结尾,里面存储的是一些辅助性的代码,绝大多数都是函数的声明
//C语言标准委员会为C语言一函数形式提供的一些基础功能,这些函数都被封装在libc.so(标准c库)
//然后通过很多的头文件对不同的功能的标准库函数进行了说明,stdio.h就是其中之一,常用:stdlib.h
//string.h

//源文件:以.c结尾,里面存储的是实际的功能性代码
int main()
    //int 是一种数据类型,表示main函数的执行结果是一个整数值 (echo $?)
    //C语言中函数是管理代码的最小单位,一个函数就是一个功能的实现
    //main函数是整个程序的入口,有且只有一个
    //main函数是由操作系统调用的,所以它的返回值给了操作系统,反映了程序是如何结束的
{
    
    printf("Hello World!\n");
    //printf/scanf是标准库的输出输入函数,一般用于调试代码
    //转义字符:键盘上有一些不好直接表示的符号,通过一些特殊的字符搭配来表示,这种字符搭配称为
    //转义字符
    //  \n 换行; \t 制表符,Tab键; \a 铃响;
    //  \b 光标后退一个字符;printf("\b \b")  退格
    //  \r 光标回到行首; %%显示一个%; \\显示一个\
    //注意:C语言是以分号作为一行代码的结束标志,使用大括号来划分代码
    return 0;
    //return的作用:
    //1.返回一个执行结果给函数的调用者   
    //0:一切正常  正数:出现异常(别人导致) 负数:出现错误(自己导致)
    //2.提前结束函数
    //main函数遇到return语句程序结束
}

编译器


负责把人看的懂的文本文件,翻译成计算机能看的懂的二进制文件,过程叫做编译。

由预处理器、编译器、链接器组成。

gcc编译器是GNU社区为了编译Linux内核代码而开发的一款免费的编译器,默认语法标准是C99或者C89

常用编译参数:

-E:只显示预处理的结果

-S:生成汇编文件

-c:只编译不链接

-o:指定编译结果的名字

-I:指定头文件的加载路径 -I path

-l:指定要使用的代码库 -lm导入数学库

-Wall:尽可能多的产生警告信息

-Werror:把警告当错误处理

-std:设置编译语法标准 -std=gnu89/99

C代码如何从源文件变成可执行文件的过程:


1.预处理:把源文件翻译成预处理文件

gcc -E xxx.c 显示预处理结果到终端

gcc -E xxx.c -o xxx.i 把预处理的结果存储到xxx.i预处理文件中

2.编译:把预处理文件翻译成汇编文件

gcc -S xxx.i 生成以.s结尾的汇编文件

3.汇编:把汇编文件翻译成二进制的目标文件

gcc -c xxx.s 生成以.o结尾的目标文件

4.链接:把若干个目标文件合并成一个可执行文件

gcc a.o b.o c.o ... 生成a.out可执行文件

C语言中的文件类型:


.c 源文件

.h头文件

.h.gch 头文件的编译结果文件,会被优先使用

.i 预处理文件

.s 汇编文件

.o目标文件

.so共享库文件

.a 静态库文件

C语言

一、数据类型


1、现实中的数据就是自带类别属性的

2、对数据进行分类可以节约内存存储空间,提高运行速度

存储空间的单位:

Bit 比特 存储一个二进制位,只能存储0或者1,是计算机存储数据的最小单位

Byte 字节 存储八个二进制位,是计算机存储数据的基本单位

Kb 1024字节

Mb 1024Kb

Gb 1024Mb

Tb 1024Gb

Pb 1024Tb

C语言中数据分为两大类:

自建(程序员自己设计的)、内建(C语言自带的)

sizeof:可以计算类型/变量所占内存字节数

内建:
整型:

signed 有符号:二进制位最高位作为符号位 0正数 1负数

类型名 字节数 数据范围

signed char 1 -128~127

signed short 2 -32768~32767

signed int 4 +-20亿

signed long 4(操作系统32位)/8(操作系统64位) +-20亿/+-9开头的19位整数

signed long long 8 +-9开头的19位整数

注意:signed不加就代表加了 char == signed char

unsigned 无符号:二进制位最高位作为数据位

类型名 字节数 数据范围

unsigned char 1 0~255

unsigned short 2 0~65535

unsigned int 4 0~40亿

unsigned long 4(操作系统32位)/8(操作系统64位) 0~40亿/0~1开头的20位整数

unsigned long long 8 0~1开头的20位整数

注意:由于定义无符号数据时比较麻烦,标准库中把这些类型重新定义成了新的类型名;

需要包含头文件<stdint.h>

uint8_t uint16_t uint32_t uint64_t //数字代表bit数
浮点型:

类型名 字节数

float 4 单精度浮点型

double 8 双精度浮点型

long double 12(操作系统32位)/16(操作系统64位)

注意:采用科学计数法、在二进制与真实数据之间需要进行换算过程,因此浮点数的运算使用速度比整型要慢得多,所以编程时尽量使用整型

注意:大多数操作系统只对小数点后6位有效

模拟型:

字符型:char

整数类型占位符:%hhd 字符类型占位符:%c

字符:就是图案或符号 ,字符在内存中依然存储成整数,需要显示成字符时,操作系统会根据ASCII码表中的对应关系,把整数显示成对应的符号或图案

'\0' 0 特殊字符 空字符

'0' 48

'A' 65

'a' 97

布尔型:bool

先有C语言,后有的bool类型,C语言中不可能有真正的布尔类型,都是在<stdbool.h>中对布尔类型使用整数进行模拟

二、变量与常量


什么是变量:

在程序运行期间值可以发生变化的叫做变量,相当于存放数据的的盒子

定义:

类型名 变量名;

int num;

取名规则:

1、由字母、数字、下划线组成

2、不能以数字开头

3、不能与C语言32个关键字重名

数据类型相关:
        内建类型:
               char  short  int  long  void  float  double                                 7
        自建类型:
               struct  union  enum  sizeof                                                  4    
        类型限定符:
                 auto  const  static  volatile  register typedef extern signed unsigned     9
流程控制相关:
        分支:
            if   else    switch  case  default                                         5
        循环:
            for  while  do                                                              3
        跳转:
            break   continue   goto   return                                           4

4、见名知意(功能、类型、范围)

注意:变量的初始值默认是随机的,为了安全起见,一般会在定义时初始化为0

使用:

赋值: 变量名 = val;

运算: 变量名*10

变量的输入、输出:
int print(const char *format,...);

功能:输出数据

format:“提示信息+占位符”

...:变量名列表

返回值:成功输出的字符个数

类型占位符:C语言通过占位符的方式传递变量的类型

signed +

char

short

int

long

long long

占位符:

%hhd

%hd

%d

%ld

%lld

unsigned +

char

short

int

long

long long

占位符:

%hhu

%hu

%u

%lu

%llu

float

double

long double

字符型:char

%f

%lf

%LF

%c

int scanf(const char *format,...);

功能:输入数据

format:“占位符”

...:变量地址列表

注意:scanf需要变量类型和地址

变量地址 == &变量名

返回值:成功输入的变量个数

什么是常量:

在程序运行期间数值不变化的叫做常量

10 默认int类型

10l long类型

10ll long long类型

10u unsigned int类型

10lu unsigned long类型

10llu unsigned long long类型

3.14 默认double类型

3.14f float类型

3.14l long double类型

三、数据的格式化输出


%nd:显示n个字符宽度,不足时补空格,右对齐

%-nd:显示n个字符宽度,不足时补空格,左对齐

%0nd:显示n个字符宽度,不足时补0,右对齐

%n.mf:显示n个字符宽度(小数点也算一位),不足时补空格,右对齐;m表示小数点后显示的位数(四舍五入)

%g:不显示小数点后多余的0;

四、运算符


自变运算符:

++/-- 让变量的值自动+1或-1

前自变:++/--num 立即生效

后自变:num++/-- 下一行语句才生效

注意:不要在一行代码内多次运用自变运算符

算术运算符:

(+ - / * %)

整数/整数 只保留整数部分

/ % 除数不能为0,否则会在运行时出现浮点数例外(核心已转储)

% 不能对浮点数求余

关系运算符:

== ! = > < >= <=

会得到比较的结果是1(成立)或0(不成立),比较的结果还可以继续参与运算

int n = -10;
10 < n < 100;  //永远为真

注意:常量建议放在 == != 的左边,防止少写一个=

逻辑运算符:

&& || ! (单目)

会先把运算对象转换成逻辑值:非零转为真,0转为假

A && B 一假即假

A || B 一真即真

!A 求反

&&和||的短路特性:当左边部分的值已经可以确定整个逻辑运算符的结果时,那么右边部分不执行;也可以借助短路特性实现简单的单分支效果

三目运算符:

A ? B : C(printf("three:%d\n",num < 9 ? 88:99))

判断A的值,如果为真(非0)则执行B,否则执行C

赋值运算符:

= += -= *= ......

a+=b;a=a+b;

注意:赋值运算符的运算结果是右边赋的数据

位运算符:

二进制下才能位运算

<< >> & | ~ ^

& 按位相与(有0为零,全1为1)

| 按位相或(有1为1,全0为0)

~ 按位求反

^ 按位异或(相同为0,不同为1)

<< 按位左移n位 (左边超出的丢弃,右边补0)

>> 按位右移n位 (右边超出的丢弃,左边补符号位)

sizeof:

也是一个运算符

注意:运算符是有优先级之分,如果使用时记不住的话,多加小括号

单位 算数 位 关系 逻辑 三目 赋值

五、类型转换问题


只有相同类型的数据才能进行运算,如果类型不相同的数据需要先转换成相同类型才能运算

自动类型转换:

转换规则:以不丢失数据为基础,可以适当地牺牲一些空间

1、字节少的向字节多的转

2、有符号的向无符号的转

3、整型向浮点型转

特例:当运算对象类型只是char 或者short且类型不同,编译器会做类型提升,提升为int 再运算

强制类型转换:

(新类型名)数据;

有丢失数据的风险,但是需要使用时还是得用

六、if分支语句


if(表达式)        //  单分支语句
{
    //  表达式的值为真(非0),则执行此处代码
}
if(表达式)        //  双分支语句
{
    //  表达式的值为真(非0),则执行此处代码
}
else
{
    //  表达式的值为假(0),则执行此处代码
}
if(表达式1)    //  多分支语句
{
    //  表达式1的值为真(非0),则执行此处代码
}
else if(表达式2)
{
    //  表达式2的值为真(非0),则执行此处代码
}
......
else
{
    //  如果所有表达式都为假,最后执行此处代码
}

七、switch开关语句


switch(n) // n可以是数值、表达式,结果必须是整型
{
    //default:......;break;// 先非法判断
    case val1:.....;break; // val必须是常整数,如果n等于val,则打开执行开关;break关闭执行开关
    case val2:.....;break;
    ......
    default:......;  // 如果所有case都不打开,则最后打开此开关;无论位置在哪,都会最后执行
}
// switch不可以与continue配合
// 注意:case n1 ... n3:表示在范围[n1,n3]内,会打开case开关,但是这属于GNU编译器的特有语法,不建议使用

八、for循环语句


循环:

就是一种让一段代码反复执行的方式,从而达到想要的效果

for循环一般会使用一个变量来引导循环的进行,这个变量叫做该循环的循环变量 i index

for循环的变化很灵活,但也很危险(相比于其他循环)

for([1];[2];[3])
{
    [4];
}

[1]、给循环变量赋初值 C99或C11标准才可以在此处定义变量(改~/.vimrc)

在for循环内定义变量,只能在for内使用,出了for循环后无法使用for循环内定义的变量,会屏蔽循环外定义的同名变量

[2]、判断循环变量是否到达结束边界值。如果判断为假,那么结束循环;反之,继续循环

[4]、被反复执行的代码,称为循环体

[3]、改变循环变量的值,防止出现死循环,一般对循环变量自加或自减

顺序:1、2、4、3、2、4、3、2......2

for的多种写法:
for(;;)
{
    // 死循环
}
int i=0;
for(;i<10;i++)
{
    
}
for(int i=0;i<10;)
{
    if(xxx)
    {
        i++;
    }
}

for循环的大括号问题:

1、for循环内只有一段代码时,大括号可以省略,但是这样不利于后期代码扩展,一般的商业代码要求大括号不能省略

2、建议上下对齐,括号内改缩进的要缩进

九、while循环语句


当条件为真时执行循环体,为假时结束循环

 while(条件)
 {
     // 循环体
 }
 // 相当于
 for(;条件;)
 {

 }
 // while循环相当于for循环其中一个精简版本
 // for循环是负责解决明确知道循环次数的问题
 // while循环是负责只知道循环结束条件而不确定循环次数的问题

十、do-while循环语句


do{
        // 循环体
}while(条件);// 分号不能少 
// 先执行循环体,在判断循环条件,至少会执行一次
// 适合先干活,再判断的特殊情况,例如:输入密码

十一、循环嵌套


循环语句中有循环语句

外层循环执行一次,内层循环执行n次

十二、跳转语句


goto:

可以在函数任意跳转

标签名:

xxx:

goto 标签名;

注意:goto很容易破坏已经设计好的分支或者循环语句,绝大多数公司时禁止使用goto的、goto在驱动编程和硬件编程中非常适合处理异常

break:

1、在switch语句中关闭case开关

2、跳出循环,如果有循环嵌套时,只能跳出最近一层循环

continue:

结束本次循环,直接进入下一次循环

return:

1、返回一个返回值给函数的调用者

2、提前结束函数,程序回到调用位置继续执行

十三、数组


什么是数组:

变量的组合,是一种批量定义相同类型变量的方式

定义:类型名 数组名[数量];

注意:数组的长度一旦确定,无法改变

使用:数组名[下标];

下标:从0开始,范围从0~数量-1

遍历:把数组的数据从头到尾显示或访问

一般与for循环配合,把循环变量 i 当作数组下标

初始化:

类型名 数组名[数量] = {1,2,3,4,5,...};

1、数组与变量一样,默认值随机,所以一般都要先初始化

2、数组不能整体初始化,只能逐个初始化

int arr[20] = 0; //错误!

3、这种初始化的语法只能在定义数组时使用

4、初始化数据过多,编译器会产生警告并丢弃多余数据

5、初始化数据不足,编译器会自动补0

6、初始化数据可以全部省略,但是要写{ },相当于全部成员初始化为0

7、如果有初始化数据,则可以省略数组数量,编译器会自动统计数据的个数,然后确定数组的数量

计算数组的总字节:

sizeof(arr)

计算数组成员的字节数:

sizeof(arr[0])

计算数组长度:

sizeof(arr)/sizeof(arr[0])

数组越界问题:

为了程序的运行效率考虑,C语言不检查数组下标是否越界

数组越界的后果:

1、一切正常

2、段错误(核心已转储)

3、脏数据

二维数组

一维数组相当于把变量排成一排,通过编号来访问

二维数组相当于把变量排成一个矩阵,通过行号和列号访问

二维数组在内存中依然是连续存储的

定义:

类型名 数组名[行数] [列数];

int arr[4] [5];

使用:数组名[行下标] [列下标];

行下标:0~行数-1

列下标:0~列数-1

遍历:一般需要与双层for循环配合,外层循环负责遍历行,内层循环负责遍历列

初始化:类型名 数组名[行数] [列数]={{第一行},{第二行},...};

注意:1、大括号内数据可以全部省略,那么就自动补0;

2、大括号数据和列数不省略,行数可以省略,编译器会自动计算行数

3、不能省略二维数组的列数

变长数组

定义数组时,使用变量作为数组的长度,这种数组称为变长数组

特点:在代码编译期间数组的长度是不确定的,当执行到数组的定义语句时长度才最终确定下来,并且一旦确定,长度无法改变

优点:可以根据实际情况来确定数组的长度,从而节约内存

缺点:初始化发生在编译期间,而可变长数组的长度的确定发生在运行期间,因此可变长数组无法初始化

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值