avatar

目录
C语言笔记

参考:【itheima】

[TOC]

C语言概述

第一个C程序

Hello World

c
1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
//这是第一个C语言代码
printf("hello world\n");
return 0;
}

gcc编译器

1) gcc编译器介绍

​ 编译器是将高级计算机语言翻译为低级机器语言的程序。

​ gcc(GNU Compiler Collection,GNU 编译器套件),是由 GNU 开发的编程语言编译器。gcc原本作为GNU操作系统的官方编译器,现已被大多数类Unix操作系统(如Linux、BSD、Mac OS X等)采纳为标准的编译器,gcc同样适用于微软的Windows。

​ gcc最初用于编译C语言,随着项目的发展gcc已经成为了能够编译C、C++、Java、Ada、fortran、Object C、Object C++、Go语言的编译器大家族。

2) 编译命令使用

格式

Code
1
2
gcc [-option1] ... <filename>
g++ [-option1] ... <filename>

常用选项说明

选项 含义
-o file 指定生成的输出文件名为file
-E 只进行预处理
-S(大写) 只进行预处理和编译
-c(小写) 只进行预处理、编译和汇编

使用(Linux下):

Code
1
2
3
gcc hello.c  //没有指定可执行程序文件名,默认生成a.out
./a.out //执行
gccc hello.c -o hello //指定名字

3)win下gcc环境配置

代码分析

Code
1
2
3
4
5
6
7
1. #include< > 与 #include ""的区别:
< > 表示系统直接按系统指定的目录检索
"" 表示系统先在 "" 指定的路径(没写路径代表当前路径)查找头文件,如果找不到,再按系统指定的目录检索
2. return语句
main定义的时候前面是void,那么return后面什么也不需要写
在main函数中return 0代表程序执行成功,return -1代表程序执行失败
int main()和void main()在C语言中是一样的,但C++只接受int main这种定义方式

system函数

使用

Code
1
2
3
4
5
6
7
#include <stdlib.h>
int system(const char *command);
功能:在已经运行的程序中执行另外一个外部程序
参数:外部可执行程序名字
返回值:
成功:不同系统返回值不一样
失败:通常是 - 1

示例

c
1
2
3
4
5
6
7
8
#include <stdio.h>
#include <stdlib.h>
int main()
{
//system("calc"); //windows平台
system("ls"); //Linux平台, 需要头文件#include <stdlib.h>
return 0;
}

C语言编译过程

C程序编译步骤

Code
1
2
3
4
5
4步:
1. 预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法
2. 编译:检查语法,将预处理后文件编译生成汇编文件
3. 汇编:将汇编文件生成目标文件(二进制文件)
4. 链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去

gcc编译过程

分步编译

Code
1
2
3
4
预处理:gcc -E hello.c -o hello.i
编 译:gcc -S hello.i -o hello.s
汇 编:gcc -c hello.s -o hello.o
链 接:gcc hello.o -o hello_elf
选项 含义
-E 只进行预处理
-S(大写) 只进行预处理和编译
-c(小写) 只进行预处理、编译和汇编
-o file 指定生成的输出文件名为 file
文件后缀 含义
.c C 语言文件
.i 预处理后的 C 语言文件
.s 编译后的汇编文件
.o 编译后的目标文件

一步编译

Code
1
gcc hello.c -o demo		//经过:预处理、编译、汇编、链接的过程

集成开发环境IDE

Qt Creator

Microsoft Visual Studio

数据类型

常量与变量

32个关键字

Code
1
2
3
4
5
6
7
8
9
10
11
1. 数据类型关键字(12个):
char short int long float double unsigned signed struct enum void
2. 控制语句关键字(12个):
A循环语句 for do while break continue
B条件语句 if else goto
C开关语句 switch case default
D返回语句 return
3. 存储类型关键字(5个):
auto extern register static const
4. 其它关键字(3个):
sizeof typedef volatile

数据类型

数据类型的作用:编译器预算对象(变量)分配的内存空间大小。

1

常量

整型常量 100,200,-100,0
实型常量 3.14 , 0.125,-3.123
字符型常量 ‘a’,‘b’,‘1’,‘\n’
字符串常量 “a”,“ab”,“12356”

变量

Code
1
2
3
4
5
6
1. 变量在编译时为其分配相应的内存空间
2. 可以通过其名字和地址访问相应内存
3. 声明和定义区别
声明变量不需要建立存储空间,如:extern int a;
定义变量需要建立存储空间,如:int b;
int b 它既是声明,同时又是定义

使用示例

c
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#define MAX 10 //声明了一个常量,名字叫MAX,值是10,常量的值一旦初始化不可改
int main()
{
int a; //定义了一个变量,其类型为int,名字叫a
const int b = 10; //定义一个const常量,名为叫b,值为10
//b = 11; //err,常量的值不能改变
//MAX = 100; //err,常量的值不能改变
a = MAX;//将abc的值设置为MAX的值
a = 123;
printf("%d\n", a); //打印变量a的值
return 0;
}

进制

C语言如何表示相应进制数

十进制 以正常数字1-9开头,如123
八进制 以数字0开头,如0123
十六进制 以0x开头,如0x123
二进制 C语言不能直接书写二进制数
c
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main()
{
int a = 123; //十进制方式赋值
int b = 0123; //八进制方式赋值, 以数字0开头
int c = 0xABC; //十六进制方式赋值
//如果在printf中输出一个十进制数那么用%d,八进制用%o,十六进制是%x
printf("十进制:%d\n",a );
printf("八进制:%o\n", b); //%o,为字母o,不是数字
printf("十六进制:%x\n", c);
return 0;
}

计算机内存数值存储方式

原码

Code
1
2
3
4
一个数的原码(原始的二进制码)有如下特点:
- 最高位做为符号位,0表示正,为1表示负
- 其它数值部分就是数值本身绝对值的二进制数
- 负数的原码是在其绝对值的基础上,最高位变为1
十进制数 原码
+15 0000 1111
-15 1000 1111
+0 0000 0000
-0 1000 0000

原码不便于加减运算

反码

Code
1
2
对于正数,反码与原码相同
对于负数,符号位不变,其它部分取反(1变0,0变1)
十进制数 反码
+15 0000 1111
-15 1111 0000
+0 0000 0000
-0 1111 1111

反码运算也不方便,通常用来作为求补码的中间过渡。

补码

Code
1
2
3
4
5
在计算机系统中,数值一律用补码来存储。
补码特点:
1. 对于正数,原码、反码、补码相同
2. 对于负数,其补码为它的反码加1
3. 补码符号位不动,其他位求反,最后整个数加1,得到原码
十进制数 补码
+15 0000 1111
-15 1111 0001
+0 0000 0000
-0 0000 0000
c
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main()
{
int a = -15;
printf("%x\n", a);
//补码符号位不动,其他位求反,最后整个数加1,得到原码
//结果为 fffffff1(计算机存储的反码)
//fffffff1对应的二进制:1111 1111 1111 1111 1111 1111 1111 0001
//符号位不变,其它取反:1000 0000 0000 0000 0000 0000 0000 1110
//上面加1:1000 0000 0000 0000 0000 0000 0000 1111 最高位1代表负数,就是-15
return 0;
}

补码的意义

示例1:用8位二进制数分别表示+0和-0

十进制数 原码
+0 0000 0000
-0 1000 0000
十进制数 反码
+0 0000 0000
-0 1111 1111

但是如果以补码方式存储,补码统一了零的编码:

十进制数 补码
+0 0000 0000
-0 10000 0000 //由于只用8位描述,最高位1丢弃,变为0000 0000

示例2:计算9-6的结果

以原码方式相加:

十进制数 原码
9 0000 1001
-6 1000 0110

结果为1000 1111 = -15,不正确。

以补码方式相加:

十进制数 补码
9 0000 1001
-6 1111 1010

相加为1 0000 0001 益处,剩余8位二进制表示的是3,正确。

在计算机系统中,数值一律用补码来存储,主要原因是:

Code
1
2
3
4
统一了零的编码
将符号位和其它位统一处理
将减法运算转变为加法运算
两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃

sizeof关键字

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
- sizeof不是函数,所以不需要包含任何头文件,它的功能是计算一个数据类型的大小,单位为字节
- sizeof的返回值为size_t
- size_t类型在32位操作系统下是unsigned int,是一个无符号的整数

*/
#include <stdio.h>
int main()
{
int a;
int b = sizeof(a);//sizeof得到指定值占用内存的大小,单位:字节
printf("b = %d\n", b);

size_t c = sizeof(a);
printf("c = %u\n", c);//用无符号数的方式输出c的值

return 0;
}

整型:int

整型变量的定义和输出

打印格式 含义
%d 输出一个有符号的10进制int类型
%o(字母o) 输出8进制的int类型
%x 输出16进制的int类型,字母以小写输出
%X 输出16进制的int类型,字母以大写写输出
%u 输出一个10进制的无符号数
c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

int main()
{
int a = 123; //定义变量a,以10进制方式赋值为123
int b = 0567; //定义变量b,以8进制方式赋值为0567
int c = 0xabc; //定义变量c,以16进制方式赋值为0xabc

printf("a = %d\n", a);
printf("8进制:b = %o\n", b);
printf("10进制:b = %d\n", b);
printf("16进制:c = %x\n", c);
printf("16进制:c = %X\n", c);
printf("10进制:c = %d\n", c);

unsigned int d = 0xffffffff; //定义无符号int变量d,以16进制方式赋值
printf("有符号方式打印:d = %d\n", d);
printf("无符号方式打印:d = %u\n", d);
return 0;
}

整型变量的输入

c
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
int a;
printf("请输入a的值:");
//不要加“\n”
scanf("%d", &a);
printf("a = %d\n", a); //打印a的值
return 0;
}

short、int、long、long long

数据类型 占用空间
short(短整型) 2字节
int(整型) 4字节
long(长整形) Windows为4字节,Linux为4字节(32位),8字节(64位)
long long(长长整形) 8字节

注意

Code
1
当一个小的数据类型赋值给一个大的数据类型,不会出错,因为编译器会自动转化。但当一个大的类型赋值给一个小的数据类型,那么就可能丢失高位。
整型常量 所需类型
10 代表int类型
10l, 10L 代表long类型
10ll, 10LL 代表long long类型
10u, 10U 代表unsigned int类型
10ul, 10UL 代表unsigned long类型
10ull, 10ULL 代表unsigned long long类型
打印格式 含义
%hd 输出short类型
%d 输出int类型
%l 输出long类型
%ll 输出long long类型
%hu 输出unsigned short类型
%u 输出unsigned int类型
%lu 输出unsigned long类型
%llu 输出unsigned long long类型
c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
int main()
{
short a = 10;
int b = 10;
long c = 10l; //或者10L
long long d = 10ll; //或者10LL

printf("sizeof(a) = %u\n", sizeof(a));
printf("sizeof(b) = %u\n", sizeof(b));
printf("sizeof(c) = %u\n", sizeof(c));
printf("sizeof(c) = %u\n", sizeof(d));

printf("short a = %hd\n", a);
printf("int b = %d\n", b);
printf("long c = %ld\n", c);
printf("long long d = %lld\n", d);

unsigned short a2 = 20u;
unsigned int b2 = 20u;
unsigned long c2= 20ul;
unsigned long long d2 = 20ull;

printf("unsigned short a = %hu\n", a2);
printf("unsigned int b = %u\n", b2);
printf("unsigned long c = %lu\n", c2);
printf("unsigned long long d = %llu\n", d2);

return 0;
}

有符号数和无符号数区别

1) 有符号数

​ 有符号数是最高位为符号位,0代表正数,1代表负数。

c
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
signed int a = -1089474374; //定义有符号整型变量a
printf("%X\n", a); //结果为 BF0FF0BA
//B F 0 F F 0 B A
//1011 1111 0000 1111 1111 0000 1011 1010(补码)
//把首位作为符号位,计算成原码后为-1089474374
return 0;
}

2) 无符号数

​ 无符号数最高位不是符号位,而就是数的一部分,无符号数不可能是负数。

c
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
unsigned int a = 3236958022; //定义无符号整型变量a
printf("%X\n", a);
//结果为 C0F00F46(补码)
//首位不是符号位,正数,其原码=反码=补码,换算后为3236958022
return 0;
}
/*
当我们写程序要处理一个不可能出现负值的时候,一般用无符号数,这样可以增大数的表达最大值。
(因为可以把原来的符号位当作数字)
*/

3) 有符号和无符号整型取值范围

2

字符型:char

字符变量的定义和输出

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
- char的本质就是一个1字节大小的整型
- 将该字符对应的 ASCII 编码放到变量的存储单元中
*/
#include <stdio.h>
int main()
{
char ch = 'a';
printf("sizeof(ch) = %u\n", sizeof(ch));

printf("ch[%%c] = %c\n", ch); //打印字符
printf("ch[%%d] = %d\n", ch); //打印‘a’ ASCII的值

char A = 'A';
char a = 'a';
printf("a = %d\n", a); //97
printf("A = %d\n", A); //65

printf("A = %c\n", 'a' - 32); //小写a转大写A
printf("a = %c\n", 'A' + 32); //大写A转小写a
ch = ' ';
printf("空字符:%d\n", ch); //空字符ASCII的值为32
printf("A = %c\n", 'a' - ' '); //小写a转大写A
printf("a = %c\n", 'A' + ' '); //大写A转小写a

return 0;
}

字符变量的输入

c
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
char ch;
printf("请输入ch的值:");

//不要加“\n”
scanf("%c", &ch);
printf("ch = %c\n", ch); //打印ch的字符
return 0;
}

ASCII对照表

ASCII 控制字符 ASCII值 字符 ASCII值 字符 ASCII值 字符
0 NUT 32 (space) 64 @ 96
1 SOH 33 ! 65 A 97 a
2 STX 34 66 B 98 b
3 ETX 35 # 67 C 99 c
4 EOT 36 $ 68 D 100 d
5 ENQ 37 % 69 E 101 e
6 ACK 38 & 70 F 102 f
7 BEL 39 , 71 G 103 g
8 BS 40 ( 72 H 104 h
9 HT 41 ) 73 I 105 i
10 LF 42 * 74 J 106 j
11 VT 43 + 75 K 107 k
12 FF 44 , 76 L 108 l
13 CR 45 - 77 M 109 m
14 SO 46 . 78 N 110 n
15 SI 47 / 79 O 111 o
16 DLE 48 0 80 P 112 p
17 DCI 49 1 81 Q 113 q
18 DC2 50 2 82 R 114 r
19 DC3 51 3 83 S 115 s
20 DC4 52 4 84 T 116 t
21 NAK 53 5 85 U 117 u
22 SYN 54 6 86 V 118 v
23 TB 55 7 87 W 119 w
24 CAN 56 8 88 X 120 x
25 EM 57 9 89 Y 121 y
26 SUB 58 : 90 Z 122 z
27 ESC 59 ; 91 [ 123 {
28 FS 60 < 92 / 124 |
29 GS 61 = 93 ] 125 }
30 RS 62 > 94 ^ 126 `
31 US 63 ? 95 _ 127 DEL
Code
1
2
3
ASCII 码大致由以下两部分组成:
1. ASCII 非打印控制字符: ASCII 表上的数字 0-31 分配给了控制字符,用于控制像打印机等一些外围设备。
2. ASCII 打印字符:数字 32-126 分配给了能在键盘上找到的字符,当查看或打印文档时就会出现。数字 127 代表 Del 命令。

转义字符

转义字符 含义 ASCII**码值(十进制)**
\a 警报 007
\b 退格(BS) ,将当前位置移到前一列 008
\f 换页(FF),将当前位置移到下页开头 012
\n 换行(LF) ,将当前位置移到下一行开头 010
\r 回车(CR) ,将当前位置移到本行开头 013
\t 水平制表(HT) (跳到下一个TAB位置) 009
\v 垂直制表(VT) 011
\ 代表一个反斜线字符”" 092
' 代表一个单引号(撇号)字符 039
" 代表一个双引号字符 034
? 代表一个问号 063
\0 数字0 000
\ddd 8进制转义字符,d范围0~7 3位8进制
\xhh 16进制转义字符,h范围09,af,A~F 3位16进制

注意: \a–\v 为不可打印字符。

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main()
{
printf("abc");
printf("\refg\n"); //\r切换到句首, \n为换行键

printf("abc");
printf("\befg\n");//\b为退格键, \n为换行键

printf("%d\n", '\123');// '\123'为8进制转义字符,0123对应10进制数为83
printf("%d\n", '\x23');// '\x23'为16进制转义字符,0x23对应10进制数为35

return 0;
}

数值溢出

Code
1
2
- 当超过一个数据类型能够存放最大的范围时,数值会溢出。
- 有符号位最高位溢出的区别:符号位溢出会导致数的正负发生改变,但最高位的溢出会导致最高位丢失。
数据类型 占用空间 取值范围
char 1字节 -128到 127(-27 ~ 27-1)
unsigned char 1字节 0 到 255(0 ~ 28-1)
c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
int main()
{
char ch;

//符号位溢出会导致数的正负发生改变
ch = 0x7f + 2; //127+2
printf("%d\n", ch);
// 0111 1111
//+2后 1000 0001,这是负数补码,其原码为 1111 1111,结果为-127

//最高位的溢出会导致最高位丢失
unsigned char ch2;
ch2 = 0xff+1; //255+1
printf("%u\n", ch2);
// 1111 1111
//+1后 10000 0000, char只有8位最高位的溢出,结果为0000 0000,十进制为0

ch2 = 0xff + 2; //255+1
printf("%u\n", ch2);
// 1111 1111
//+1后 10000 0001, char只有8位最高位的溢出,结果为0000 0001,十进制为1

return 0;
}

实型(浮点型):float、double

数据类型 占用空间 有效数字范围
float 4字节 7位有效数字
double 8字节 15~16位有效数字
c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
- 不以f结尾的常量是double类型,以f结尾的常量(如3.14f)是float类型。
- 由于浮点型变量是由有限的存储单元组成的,因此只能提供有限的有效数字。在有效位以外的数字将被舍去,这样可能会产生一些误差。

*/
#include <stdio.h>
int main()
{
//传统方式赋值
float a = 3.14f; //或3.14F
double b = 3.14;

printf("a = %f\n", a);
printf("b = %lf\n", b);

//科学法赋值
a = 3.2e3f; //3.2*1000 = 32000,e可以写E
printf("a1 = %f\n", a);

a = 100e-3f; //100*0.001 = 0.1
printf("a2 = %f\n", a);

a = 3.1415926f;
printf("a3 = %f\n", a); //结果为3.141593

return 0;
}

类型限定符

限定符 含义
extern 声明一个变量,extern声明的变量没有建立存储空间。 extern int a;
const 定义一个常量,常量的值不能修改。 const int a = 10;
volatile 防止编译器优化代码
register 定义寄存器变量,提高效率。register是建议型的指令,而不是命令型的指令,如果CPU有空闲寄存器,那么register就生效,如果没有空闲寄存器,那么register无效。

字符串格式化输出和输入

字符串常量

Code
1
2
3
- 字符串是内存中一段连续的char空间,以'\0'(数字0)结尾。

- 字符串常量与字符常量的不同:每个字符串的结尾,编译器会自动的添加一个结束标志位'\0',即 "a" 包含两个字符'a'和’\0’

printf函数和putchar函数

​ printf是输出一个字符串,putchar输出一个char。

printf格式字符:

打印格式 对应数据类型 含义
%d int 接受整数值并将它表示为有符号的十进制整数
%hd short int 短整数
%hu unsigned short 无符号短整数
%o unsigned int 无符号8进制整数
%u unsigned int 无符号10进制整数
%x,%X unsigned int 无符号16进制整数,x对应的是abcdef,X对应的是ABCDEF
%f float 单精度浮点数
%lf double 双精度浮点数
%e,%E double 科学计数法表示的数,此处”e”的大小写代表在输出时用的”e”的大小写
%c char 字符型。可以把输入的数字按照ASCII码相应转换为对应的字符
%s char * 字符串。输出字符串中的字符直至字符串中的空字符(字符串以’\0‘结尾,这个’\0’即空字符)
%p void * 以16进制形式输出指针
%% % 输出一个百分号

printf附加格式:

字符 含义
l(字母l) 附加在d,u,x,o前面,表示长整数
- 左对齐
m(代表一个整数) 数据最小宽度
0(数字0) 将输出的前面补上0直到占满指定列宽为止不可以搭配使用-
m.n(代表一个整数) m指域宽,即对应的输出项在输出设备上所占的字符数。n指精度,用于说明输出的实型数的小数位数。对数值型的来说,未指定n时,隐含的精度为n=6位。
c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
int main()
{
int a = 100;
printf("a = %d\n", a);//格式化输出一个字符串
printf("%p\n", &a);//输出变量a在内存中的地址编号
printf("%%d\n");

char c = 'a';
putchar(c);//putchar只有一个参数,就是要输出的char
long a2 = 100;
printf("%ld, %lx, %lo\n", a2, a2, a2);

long long a3 = 1000;
printf("%lld, %llx, %llo\n", a3, a3, a3);

int abc = 10;
printf("abc = '%6d'\n", abc);
printf("abc = '%-6d'\n", abc);
printf("abc = '%06d'\n", abc);
printf("abc = '%-06d'\n", abc);

double d = 12.3;
printf("d = \' %-10.3lf \'\n", d);

return 0;
}

scanf函数与getchar函数

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>

int main()
{
char ch1;
char ch2;
char ch3;
int a;
int b;

printf("请输入ch1的字符:");
ch1 = getchar();
printf("ch1 = %c\n", ch1);

getchar(); //测试此处getchar()的作用,回车

printf("请输入ch2的字符:");
ch2 = getchar();
printf("\'ch2 = %ctest\'\n", ch2);

getchar(); //测试此处getchar()的作用
printf("请输入ch3的字符:");
scanf("%c", &ch3);//这里第二个参数一定是变量的地址,而不是变量名
printf("ch3 = %c\n", ch3);

printf("请输入a的值:");
scanf("%d", &a);
printf("a = %d\n", a);

printf("请输入b的值:");
scanf("%d", &b);
printf("b = %d\n", b);

return 0;
}

运算符与表达式

文章作者: Machine
文章链接: https://machine4869.gitee.io/2018/02/24/15326721810026/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 哑舍
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论