C语言入门——Linux系统

一、C语言介绍

丹尼斯.里奇和肯.汤普逊于1971~1973年在贝尔实验室,在开发UNIX操作系统时,以BCPL语言为基础研发了一款高级编程语言,取BCPL的第二个字母作为名字,所以叫C语言。

它是为了开发操作系统而研发的一款编程语言,它特别擅长控制硬件,所以在服务器、驱动编程、单片机、嵌入式使用较多。

C语言的优点:

1、语法简单,只有32个关键字,入门简单。

2、执行速度快能媲美汇编语言的执行速度,也适合用于实现算法。

C语言的缺点:

1、需要对内存、操作系统有一定的了解,易学难精。

2、由于出现的较早个人计算机还没普及,所以在设计时没有为普通人考虑太多,有一些语法上的陷阱和缺陷。

3、没有大型的软件公司在背后支持,可用的软件库比较少。

二、第一个C程序

#include <stdio.h>
​
int main(int argc,const char* argv[])
{
    printf("Hello World!\n");
    return 0;
}
编译执行:
# 编译代码,生成可执行文件,如果代码没有错误,会生成a.out可执行程序。
gcc hello.c
​
# 执行程序
./a.out 
详解Hello World:

1、程序员所编写的代码并不是标准C代码,它需要一段程序把它翻译成标准的C代码,负责翻译的程序叫预处理器,被翻译的代码叫预处理指令,所有的预处理指令都是以#开头。

2、#include 就是预处理指令,它的功能是导入一个辅助文件到当前文件。

#include "filename.h" // 用于导入自定义的头文件
#include <filename.h> // 用于导入系统提供的头文件(标准库、操作系统)

3、C语言标准委员会为C语言以函数形式提供了一些基础功能,这些函数被封装在libc.so库文件中,并且提供了一些辅助说明文件,常用的有:stdio.h、stdlib.h、string.h等。

4、stdio.h头文件是 stdandard input output的缩写,里面对输入输入数据的函数进行了说明,当我们在代码中使用输入、输出数据的函数时,就需要包含该文件。

5、在C语言中,函数是管理代码的最小单位,一个函数就一段具有某项功能的代码,main函数是C程序默认的执行入口,入口有且仅有一个,无论它定在任何位置都最先执行。

6、函数名后面的内容是函数调用者传递给函数的数据,在命令行执行程序时,后面可以附带一些数据传递给main函数。

7、函数前面的内容是一种数据类型,它表示函数的执行结果是什么类型的数据,int指的就是整型。

8、C语言中使用大括号划分代码区域,被大括号包含的代码都属于main函数的函数体。

9、printf/scanf是标准库的函数,用于输出、输入数据,一般用于调试程序。

// printf在输出数据会有一些不方便输入的字符有特殊的字符表示(转义字符):
    \n 换行
    \r 回到行首
    \b 退格
    \t 制表符
    %% 输出一个%
    \\ 输出一个\

10、return语句有两项功能,结束函数的执行,当执行到retunr语句时,那怕后面还有代码都不会再执行了,另外可以返回一个数据给函数的调用者,main函数的调用者就是操作系统。

11、main函数的返回值表示了程序的结束状态: ​ return 正数,表示程序执行出现异常。 ​ return 0,表示程序正常结束。 ​ return 负数,表示程序执行出现错误。 ​ echo $? 查看main函数的返回值

12、C代码中以分号作为一行代码的结束标志,如果代码过长可以换行。

三、编译器和gcc

1、什么是编译器

它是一个负责翻译代码的程序,它负责把人类能看懂的代码翻译成计算机能理解的二进制指令,它由预处理器、编译器、汇编器、链接器组成,统称为编译器。

gcc 是GNU组织为了编译Linux内核代码而开发一款C语言编译器。

2、gcc编译器把C代码变成可执行程序的过程
1、把程序员所编写的代码进行预处理
#  把预处理的结果显示到屏幕上
gcc -E hello.c
​
# 会生成以.i结尾的预处理文件

gcc -E hello.c -o hello.i
2、把预处理的结果翻译成汇编代码
# 会生成以.s结尾的汇编文件
gcc -S hello.i
3、把汇编代码翻译成二进制指令
# 会生成以.o结尾的目标文件
gcc -c hello.s 
4、把若干个文件目标文件、库文件合并成可执行文件
# 默认会生成a.out可执行文件·

gcc a.o b.o c.o ... 
​
# 也可以使用-o指定可执行文件的名字。

gcc hello.o -o hello
​
# 执行程序

./hello 
​
# 编译执行:
gcc a.o b.o c.o && ./a.out

注意:gcc hello.c 就包含了以上四个步骤,了解这个步骤是我们后续学习预处理指令、多文件编程、静态库、动态库的基础。

3、gcc编译器常用的参数(了解):
-E 预处理
-S 生成汇编文件
-c 生成目标文件
-o 设置编译结果的名字
-I 设置要导入的头文件的路径
-l 设置要链接的库名,例如:使用sqrt、pow等数学函数时就需要链接数学库 -lm
-L 设置要链接的库的路径
-D 在编译时定义宏
-g 编译时添加调试信息,这样编译出的程序可以用gdb调试。
-Wall 显示所有警告,编译器会以更严格的标准检查代码 
-Werror 把警告当错误处理
-std 指定编译器要遵循的语法标准,c89,c99,c11,当前系统默认的是c99标准。
4、C语言的文件类型(了解):
.h 头文件,里面是一些对.c文件的说明
.c 源文件,里面是一些功能型代码
.i 预处理文件
.s 汇编文件
.o 目标文件
.gch 头文件的编译结果,用于检查自定义的头文件是否有语法错误,建议立即删除
.a 静态库文件,相当Windows系统下的.lib文件
.so 动态库文件,相当Windows系统下的.dll文件

四、C语言中基本的数据类型

C语言为什么要把数据分为不同的类型:

数据存储计算机中需要耗费存储空间(内存、硬盘),在编程语言中把数据按照使用范围、特点划分为不同的种类,解决什么问题使用什么类型的数据,这样可以节约存储空间、提高运算速度,这是程序员的基本功。

整型:
有符号整型:

最高位的二进制用于表示正负,0代表正数,1代表负数。 ​ 由于有符号整型使用较多,所以编译器默认signed可以省略,不加就代表加。

类型名         占用内存字节数     取值范围
signed char         1       -128 ~ 127
signed short        2       -32768 ~ 32767
signed int          4       -2147483648 ~ 2147483647
signed long         4|8
signed long long    8       -9223372036854775808 ~ 9223372036854775807
无符号整型:

所有的二进制位都用来表示数据,只能表示正数。

类型名         占用内存字节数 最大值
unsigned char       1       255
unsigned short      2       65535
unsigned int        4       4294967295
unsigned long       4|8 
unsigned long long  8       18446744073709551615
    
无符号类型一般用于计数,unsigned 不能省略,使用起来比较麻烦,标准库为了让我们方便使用,在stdint.h 头文件中对它们进行的类型重定义,分别是:
 
       uint8_t uint16_t uint32_t uint64_t size_t
浮点型:

小数点是浮动的,也就是带小数点的数据,采用科学计算数法存储,由符号位+指数域+小数域组成,这种存储格式,运算速度慢、又不太准确,所以尽量少用。

单精度: float           4
双精度: double          8
高精度: long double     12|16
注意:小数点后六位有效。
字符型:

char 字符型,字符就是符号或图案,但在计算机中以整数形式存储(使用整数模拟字符),当需要显示时根据ASCII表中的对应关系显出相应的符号或图案。

bool 布尔型:

C语言中没有真正的布尔类型,因为先有的C语言后出现的布类型,在C89之后以打补丁的方式新增布尔类型,需要包含stdbool.h头文件。

bool    1字节
true    4字节 实际使用的是整数1
false   4字节 实际使用的是整数0

注意:复合数据类型结构、联合、枚举、指针,后期会详细讲解。

五、变量

什么是变量:

在程序运行过程可以变化的量,它是存储数据的容器,需要先定义才能使用。

定义变量:

数据类型 <变量名>;

1、变量的所占用的内存字节数、存储数据的范围、使用的规则都由变量的类型决定。

2、变量的定义就是操作系统把一个标识符与内存建议映射关系,操作系统不会对这个内存进行初始化,所以变量的默认值是不确定的,我们要对一些特殊用途的变量进行初始化,比如:计数、求和、平均、累加。

3、定义的变量,出了它所在的大括号就不能再使用了。

4、定义变量后,操作系统会帮我们把变量名与一块内存建立映射关系,操作系统并不会帮我们把这块内存进行初始化,所以变量的默认是随机的、不确定的,特殊用途的变量要进行初始化为0,比如:计数、求和、累加。

变量的取名规则:

1、由数字、字母、下划线组成。 ​ 2、不能以数字开头。 ​ 3、不能与关键字重名(C语言中有32个关键字)。 ​ 4、见名知义,类型、功能、使用范围、归属模块。

特殊的合法的变量名:

bool,printf,true,flase

非法变量名举例:

1num、*num、auto

变量的使用:

num = 0; // 被赋值、存储数据,相当是个容器 ​ num*3/4; // 参与运算,此时变量名就代表它存储的数据

变量的输出:

在实际项目中变量没有输入、输出的需求,但在调试阶段,我们为了检查程序的运行是否正确,一般使用printf函数输出变量的值,模拟把数据显示在界面上,使用scanf输入变量的值,模拟从界面获取用户输入的数据。

#include <stdio.h>
​
int printf(const char *format, ...);
功能:它是C标准库函数,把若干数据输出到终端上
format:提示信息+变量的类型信息+转义字符 
...:若干个变量名,变量名之间有逗号分隔
返回值:printf输出到终端上的字符个数,一般不使用
   
在C语言中使用占位符来表示变量的类型:
    %hhd %hd %d %ld %lld  有符号整型的占位符    
    %hhu %hu %u %lu %llu  无符号整型的占位符
    %f %lf %Lf  浮点型的占位符
    %c 字符型的占位符
    布尔类型是用来逻辑运算的,不参与输入、输出,如果要强行输出,把它当整型即可。
变量的输入:
int scanf(const char *format, ...);
功能:从终端读取数据赋值给变量
format:占位符,提示信息和转义字符不要使用
...:若干个变量的地址,&变量名可以计算出变量的地址
返回值:成功读取数据的变量个数,一般不使用
    
错误的使用案例:
    scanf("%d\n",&num);

六、常量(了解)

常量就是程序运行过程中不能改变的量,C语言的常量有:字面值常量、宏常量、枚举常量。

100     int
100l    signed long
100ll   signed long long
100u    unsigned int
100lu   unsigned long
100llu  unsigned long long
    
3.14    double
3.14f   float 
3.14F   long double
'A'     char

七、运算符

算术运算符:
+   加  
-   减
*   乘
/   除   进行除法运算得到的结果是商
%   求余 进行除法运算得到的结果是余数
注意1:

整数/整数 计算的结果没有小数点,例如:5/3 的结果是1,3/5的结果是0。

注意2:

/和% 都是进行除法运算,/结果是商,%结果是余数,它们除数不以为零,会出现浮点数例外的错误,该错误会让程序立即结束。

关系运算符:
>   大于
>=  大于等于
<   小于
<=  小于等于
==  相等
!=  不相等
注意1:

它们运算结果是逻辑值,C语言中的逻辑值是用0(假)和1(真)模拟的,计算出的结果还能进行数学运算。

注意2:

与数学中的用法不同,10 < x < 100,在数学中表示是x的取值范围,但在C语言中它就是需要运算的表达式,会先计算 10 < x 得到0|1,然后再把这个结果与100比较,所以该表达的结果永远是真。

注意3:

使用==运算符时,非常容易出错误,容易漏写一个=,该错误编译器检查不出,阅读代码也很难查出来,所以在使用==时,把常量放在左边,变量写右边,这样当漏写=时,编译器会报错误。

int num;
if(num = 100)   // 变成了赋值语句,num被赋值为100,并且if分支永远执行
{
​
}
​
if(100 = num)   // 用变量给常量赋值,编译器会报错
{
​
}
逻辑运算符:
&& 与 双目运算符,左右两边都是真,结果才是真
|| 或 双目运算符,左右两边只要有一个是真,结果就是真
!  非 单运算符,只针对右边的运算对象,求反,如果运算对象是真,结果就是假,如果运算对象是假,结果就是真
注意:!比&&、||的运算优先级高。
它们会把运算对象转换成逻辑值再运算,零值转换为假,非零值转换为真,它们的运算结果也就是逻辑值。
短路特性:

当左边的值已经可以确定运算结果时,右边的不再计算,适当的使用可以实现精简的if结构,能看懂即可,不要这样写,因为它会影响代码的可读性。

(表达式1) && (表达式2) 如果表达式1结果是假,表达式2不再计算。
(表达式1) || (表达式2) 如果表达式1结果是真,表达式2不再计算。
    
num >10 && (num=0); // 等价于下面的if语句
if(num > 10)
{
    num = 0;
}
自变运算符:
前自变:++/--i
    变量的值立即加1或减1。
后自变:i++/--
    变量的值加1或减1,下一行代码有效。

该类运算符可以让变量的值自加或自减1,但只能针对变量使用。

注意:

不要在复杂表达式中过度使用自变运算符,不同的编译器对它的运算规则不同,编译器会把合适的后自变优化成前自变。

赋值运算符及扩展:
= += *= /= %=... 是变量先运行后赋值的一种精简写法
a += b; 等价  a = a + b;
a *= b; 等价  a = a * b;
三目运算符:

[A] ? [B] : [C];

它的运算对象有三个,所以叫三目运算符,先把[A]转换成逻辑值,为真执行[B],为假执行[C],相当于精简的 if else 结构。

注意:

与 if else 不同的是三目运算符必须有运算结果,所以它里面不能使用流程控制语句,比如:return、break、continue。

字节数运算符:

sizeof它不是函数,是C语言的32个关键字之一,它能计算出数据在内存需要占用的内存字节数,如果运算对象不是表达式,它可以不使用小括号。

注意:

sizeof(表达式)不会执行小括号里表达式,它只时推算表达式的执行结果是什么类型,然后计算出该类型在内存中占用多少个字节。

位运算符:

& | ~ ^ << >> 它们就针对数据的补码进行运算,后续再详细讲解。

八、类型转换

前提:只有相同类型的数据才能在一起进行运算,因为不同类型的数据,字节数不同、格式、运算规则不同,必须把不同类型的数据转换成同一类型才能运算。

自动类型转换(隐式类型转换):

不同类型的数据组成的表达式,编译器会把先它们转换成相同的类型再计算,这叫作自动类型类型或隐式类型转换,它们的转换规则是以不丢失数据为前提: ​ 1、字节数不同,字节少的向多的转换。 ​ 2、整型向浮点型转换。 ​ 3、有符号的向无符号转换。 ​ 4、char、short会先转换成int类型,如果不能满足运算条件再转换成其它。

#include <stdio.h>
​
int main()
{
    /*  
    unsigned short num1 = 10;
    short num2 = -100;
    printf("%d\n",sizeof(num1+num2));
    if(num1+num2 < 0)
        printf("小于0\n");
    else
        printf("大于0\n");
    */
    unsigned int num1 = 10; 
    int num2 = -100;
    printf("%d\n",sizeof(num1+num2));
    if(num1+num2 < 0)
        printf("小于0\n");
    else
        printf("大于0\n");
} 
强制类型转换:

(目标类型)数据,会把数据强制转换为目标类型,这种转换方式有可能会造成数据丢失,慎重使用。

九、if语句

代码的默认执行流程是从上到下,逐步、逐条执行的,if语句可以根据判断条件选择让代码是否执行,改变了代码 的默认执行流程,所以这种语句也叫流程控制语句。

if(条件) // 单分支 
{
    // 当条件为真时,执行此处代码,如果此处代码只有一行,大括号可以省略,但在商业项目中建议不要省略,因为这样会影响代码的可扩展性
}
​
if(条件)  // 双分支
{
    // 当条件为真时,执行此处代码
}
else
{
    // 当条件为假时,执行此处代码
}
​
if(条件1) // 多分支
{
    // 当条件1为真时,执行此处代码
}
else if(条件2) // 可以有多个else if
{
    // 当条件2为真时,执行此处代码
}
...
else
{
    // 当条件1、条件2都为假时,执行此处代码
}

注意:如果if、else的代码块只有一行代码,大括号可以省略,但省略大括号会降低代码的可扩展性,降低安全性。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值