前言
C是一种通用的编程语言,广泛用于系统软件与应用软件的开发。于1969年至1973年间,为了移植与开发UNIX操作系统,由丹尼斯·里奇与肯·汤普逊,以B语言为基础,在贝尔实验室设计、开发出来。 C语言具有高效、灵活、功能丰富、表达力强和较高的可移植性等特点,在程序设计中备受青睐,成为最近25年使用最为广泛的编程语言。(维基百科)
include 关键字
系统目录下的头文件
当前目录下的头文件
main函数
- main函数是C语言程序的入口
- 一个C语言程序必须有且只有一个main函数
1 2 3 4 5
| int main() { ... return 0; }
|
注释
行注释
- 这种注释方式从C++继承过来的,但是现在也可以在C语言中使用
块注释
变量命名规则
- 可以包含数字字母下划线
- 首字母不可以是数字
- 不可以为c语言内置关键字
print 函数
<str>
:一个任意类型的数据
1 2 3 4 5 6 7
| #include <stdio.h>
int main() { system(<str>); return 0; }
|
编译错误
warning
error
return 关键字
- 返回值
- 如果返回值类型为void,就不需要返回值
- 执行到return会立即结束当前函数,return后面的语句是没有意义的
main 函数的 return
- 在main函数中调用return关键字,程序立即终止
return 0
表示程序执行成功
return -1
表示程序执行失败
System 函数
- 调用system,可以再C语言的代码中执行另外一个程序
<command>
:在当前操作系统下的命令
1 2 3 4 5 6 7
| #include <stdlib.h>
int main() { system("<command>"); return 0; }
|
Linux上查看应该引入什么头文件
1 2
| man 2 print man 3 system
|
头文件存储位置
1
| vim /usr/include/stdio.h
|
解决跨平台
- 在不同平台下,C语言只能保证源码语法相同,并不一定能保证执行结果相同
- 为了解决跨平台问题,可以使用POSIX标准书写代码
- 如果有符合POSIX标准的函数,尽量使用
操作系统结构
用户模式
内核模式
- 只有系统底层的C语言程序才可以访问系统内核相关的内存
CPU
32位和64位系统的区别
- 32位CPU
- 32位寄存器可以存放32个二进制位
- 32位CPU的总线是32位
- 32位管理内存最大值为4G
- 所以在32位的系统上大于4G的内存是浪费的
- 所以在小于等于4G内存的情况下,安装64位操作系统,并不一定比32位系统快
- 如果在64位的CPU上安装64位操作系统,那么这个系统就是64位
1 2
| 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111 1111 1111 1111 1111
|
- 64位CPU
- 64位寄存器可以存放64个二进制位
- 64位CPU的总线是64位
- 64位管理内存最大值至少大于4G
- 如果在64位的CPU上安装32位操作系统,那么这个系统就是32位
1 2
| 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
|
- 准64位CPU
- 64位寄存器,总线是32位
- 运算可以达到64位的效果,但是和外部交换数据时只能是32位的速度
RISC和CISC
常量
定义常量
define
- 这种定义常量的方法叫宏常量,宏常量的常量名通常用全大写
- define通常紧跟include
- C语言通常使用define定义常量
const
- const常量变量名可以小写
- const通常写在代码内
- C++通常使用const定义常量
进制转换
十进制 |
二进制 |
八进制 |
十六进制 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
2 |
10 |
2 |
2 |
3 |
11 |
3 |
3 |
4 |
101 |
4 |
4 |
5 |
110 |
5 |
5 |
6 |
111 |
6 |
6 |
7 |
1000 |
7 |
7 |
8 |
1001 |
10 |
8 |
9 |
1010 |
11 |
9 |
10 |
1011 |
12 |
A |
11 |
1100 |
13 |
B |
12 |
1101 |
14 |
C |
13 |
1110 |
15 |
D |
14 |
1111 |
15 |
E |
15 |
10000 |
17 |
F |
16 |
10001 |
20 |
10 |
- 1二进制位 = 1比特(bit)
- 8比特 = 1字节(Byte)
- 2字节 = 1字(Word)
- 2字 = 1双字(DWord)
- 1024字节 = 1千字(KByte)
- 1024千字 = 1兆字(MByte)
- 1024兆字 = 1GByte
转化二进制
快速二进制转八进制
1 2 3
| 010 101 010 111
2 5 2 7
|
快速二进制转十六进制
无符号数和有符号数
无符号数
有符号数
- 有符号数的第一位为符号位,可以表示负数
- 范围:-125~124
原码
- 第一位为符号位,其他位表示数
- 正数符号位为0,负数符号位为1
1 2 3 4 5
| +7的原码(1Byte) 0000 0111
-7的原码(1Byte) 1000 0111
|
反码
- 如果为正数,原码和反码相同
- 如果为负数,第一位为符号位,其他位的0和1相反
1 2 3 4 5
| +7的反码(1Byte) 0000 0111
-7的反码(1Byte) 1111 1000
|
补码
- 如果为正数,反码和补码相同
- 如果为负数,第一位为符号位,其他位为反码+1
1 2 3 4 5
| +7的补码(1Byte) 0000 0111
-7的补码(1Byte) 1111 1001
|
sizeof 关键字
大端对齐与小端对齐
- 小端对齐(倒着放):高内存地址存放整数高位,低内存地址存放整数低位
- x86、ARM的CPU通常使用的是小端对齐存储方式
- 大端对齐(正着放):低内存地址存放整数高位,高内存地址存放整数低位
数据类型
传送门
类型限定关键字
const 关键字
volatile 关键字
- 当变量被频繁改变时,编译器会对代码自动优化,但这种优化有利有弊,为了防止编译器做优化,可以使用volatile关键字
register 关键字
- register是建议型指令,而不是命令型指令。如果CPU的寄存器有空闲,那么register就生效,如果没有CPU的寄存器没有空闲,那么register无效
字符串
- 字符串在内存中是一段连续的char空间,以
\0
结尾
输出一个char
<char>
:一个字符
输出一个字符串
<str>
:一个字符串
printf函数
格式化 |
对应数据类型 |
描述 |
%d |
int |
有符号十进制整数 |
%u |
unsigned int |
无符号十进制整数 |
%o |
unsigned int |
无符号八进制整数 |
%x 、%X |
unsigned int |
无符号十六进制整数 |
%ld |
long |
有符号十进制长整数 |
%lld |
long long |
有符号十进制长整数 |
%lu |
long |
无符号十进制长整数 |
%llu |
long long |
无符号十进制长整数 |
%lo |
long |
无符号八进制长整数 |
%llo |
long long |
无符号八进制长整数 |
%lx 、%lX |
long |
无符号十六进制长整数 |
%llx 、%llX |
long long |
无符号十六进制长整数 |
%hd |
short int |
短整数 |
%hu |
unsigned short int |
无符号短整数 |
%f |
float或double |
单精度浮点数或双精度浮点数 |
%e 、%E |
double |
科学记数法 |
%c |
char |
字符型 |
%s 、%S |
char* / wchar_t* |
字符串 |
%p |
void* |
(以十六进制)输出指针(数据在内存中的地址) |
%% |
% |
输出一个百分号 |
指定数据长度
用空格补齐
- 在
%
后加数字,表示输出的结果最小长度,如果不足,用空格补齐
- 如果为正数,空格在数据前补齐,数据右对齐
- 如果为负数,空格在数据后补齐,数据左对齐
用0补齐
- 在用空格补齐的基础上,再在
%
后加0
,表示用0补齐至最小长度
getchar函数
1 2 3
| #include <stdio.h>
int 变量 = getchar();
|
scanf函数
&变量名
:这个参数需要指定内存地址
VS解决报错
- 在VS2013中,VS认为scanf不安全,所以使用scanf会报错
- 解决办法有两种
- 一种是添加一个宏函数(这个宏函数一定要写到文件的第一行)
- 一种是屏蔽警告
1
| #define _CRT_SECURE_NO_WARNINGS
|
1
| #pragma warning(disable:4996)
|
运算符
传送门
分支语句
传送门
循环语句
传送门
exit 函数
1 2 3
| #include <stdlib.h>
exit(0);
|
作用域
1 2 3 4 5 6 7
| int a = 0; int main() { int a = 0; { int a = 0; } }
|
自动变量
- 代码块内部定义的都是自动变量,只不过平常我们会省略
auto
关键字
寄存器变量
静态变量
- 静态变量放在代码块内或代码块外都可以
- 静态变量只初始化一次,在程序加载到内存的时候就创建,直到程序运行结束才销毁
静态全局变量
静态全局函数
对堆内存的操作
引入头文件
返回值为一个指针
- 返回一个指针时,应该使用堆内存来操作,因为栈的生命周期只有代码块内,当代码块执行结束后,指针指向的地址就没有意义了
1 2 3 4 5 6 7 8 9 10 11 12 13
| int *a() { int a = 0; return &a }
int main() { int *p = a(); ... free(p); return 0; }
|
C语言的入栈规则
完成