前言
C是一种通用的编程语言,广泛用于系统软件与应用软件的开发。于1969年至1973年间,为了移植与开发UNIX操作系统,由丹尼斯·里奇与肯·汤普逊,以B语言为基础,在贝尔实验室设计、开发出来。 C语言具有高效、灵活、功能丰富、表达力强和较高的可移植性等特点,在程序设计中备受青睐,成为最近25年使用最为广泛的编程语言。(维基百科)
头文件
引入头文件
系统目录下的头文件
当前目录下的头文件
查看引入什么头文件
Linux
Windows
1
| printf site:learn.microsoft.com
|
头文件存储位置
Linux
Windows
Visual Studio(MSVC)
- 标准C库:
C:\Program Files (x86)\Microsoft Visual Studio\<ver>\<Edition>\VC\Tools\MSVC\<toolset-ver>\include
- WindowsSDK:
C:\Program Files (x86)\Windows Kits\10\Include\<sdk-ver>\ucrt
MinGW(轻量GCC)
- 64位
<root>\mingw64\include
<root>\mingw64\x86_64-w64-mingw32\include
<root>\mingw64\lib\gcc\x86_64-w64-mingw32\<ver>\include
- 32位:
<root>\mingw32\i686-w64-mingw32\include
Cygwin(完整GCC)
- Cygwin根:
<cygwin-root>\usr\include
- 32位GCC:
<cygwin-root>\usr\i686-pc-cygwin\include
- 64位GCC:
<cygwin-root>\usr\x86_64-pc-cygwin\include
入口函数
- main函数是C语言程序的入口
- 一个C语言程序必须有且只有一个main函数
1 2 3 4 5
| int main() { ... return 0; }
|
注释
行注释
- 这种注释方式从C++继承过来的,但是现在也可以在C语言中使用
块注释
函数返回值
- 通过
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; }
|
解决跨平台
- 在不同平台下,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定义常量
sizeof 关键字
大端对齐与小端对齐
- 小端对齐(倒着放):高内存地址存放整数高位,低内存地址存放整数低位
- x86、ARM的CPU通常使用的是小端对齐存储方式
- 大端对齐(正着放):低内存地址存放整数高位,高内存地址存放整数低位
数据类型
传送门
类型限定关键字
const 关键字
volatile 关键字
- 当变量被频繁改变时,编译器会对代码自动优化,但这种优化有利有弊,为了防止编译器做优化,可以使用volatile关键字
register 关键字
- register是建议型指令,而不是命令型指令。如果CPU的寄存器有空闲,那么register就生效,如果没有CPU的寄存器没有空闲,那么register无效
字符串
- 字符串在内存中是一段连续的char空间,以
\0结尾
输出一个char
<char>:一个字符
输出一个字符串
<str>:一个字符串
输出语句
格式化输出
1 2 3 4 5 6 7
| #include <stdio.h>
int main() { printf("%d", 0); return 0; }
|
| 格式说明符 |
数据类型 |
描述 |
%hd |
short int |
短整型数据 |
%hu |
unsigned short int |
无符号短整型数据 |
%d |
int |
有符号十进制整型数据 |
%u |
unsigned int |
无符号十进制整型数据 |
%o |
unsigned int |
无符号八进制整型数据 |
%x |
unsigned int |
无符号十六进制整型数据,字母小写 |
%X |
unsigned int |
无符号十六进制整型数据,字母大写 |
%ld |
long |
有符号十进制长整型数据(32位或64位) |
%lu |
unsigned long |
无符号十进制长整型数据(32位或64位) |
%lo |
unsigned long |
无符号八进制长整型数据(32位或64位) |
%lx |
unsigned long |
无符号十六进制长整型数据,字母小写(32位或64位) |
%lX |
unsigned long |
无符号十六进制长整型数据,字母大写(32位或64位) |
%lld |
long long |
有符号十进制长整型数据(64位) |
%llu |
unsigned long long |
无符号十进制长整型数据(64位) |
%llo |
unsigned long long |
无符号八进制长整型数据(64位) |
%llx |
unsigned long long |
无符号十六进制长整型数据,字母小写(64位) |
%llX |
unsigned long long |
无符号十六进制长整型数据,字母大写(64位) |
%f |
float、double |
单精度浮点型数据或双精度浮点型数据 |
%e |
double |
双精度浮点型数据,科学记数法,字母小写 |
%E |
double |
双精度浮点型数据,科学记数法,字母大写 |
%c |
char |
字符型数据 |
%s |
char* |
单字节字符串型数据 |
%S |
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 8 9 10 11
| 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语言的入栈规则
完成