工作需要近期接触 C++ 利用空闲时间整理输出一下个人总结,希望给一起学习的伙伴们分享一下学习历程,也是鞭笞自己不能有所放松.因个人能力有限,如有错误的地方或是意见还请留言指出,谢谢
C语言基础 (一)
1.C语言概述
1.1 第一个C语言程序:hello world
1.1.1 编写C语言代码:hello.c
#include //包含头文件 std标准库 io入输出库
int main(void)
{
printf("hello world! \n");
return 0;
}
1.1.2 通过gcc编译C代码
编译命令格式:
gcc [-option1] ...
g++ [-option1] ...
1.1.3 代码分析
1.2 system 函数
1.2.1 system 函数的使用
#include
int system(const char *command);
// 功能: 在已经运行的程序中执行另一个外部程序
// 参数: 外部可执行程序名字或命令
// 返回值: 成功:不同系统返回值不一样 失败:通常为 -1
示例代码:
#include
#include
int main()
{
//system("calc"); //windows平台
system("ls"); //Linux平台, 需要头文件#include
return 0;
}
1.3 C 语言编译过程
1.3.1 C语言编译步骤
C代码编译成可执行程序经过4步:
1)预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法
2)编译:检查语法,将预处理后文件编译生成汇编文件
3)汇编:将汇编文件生成目标文件(二进制文件)
4)链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去
1.3.2 gcc 编译过程
分布编译
预处理: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
一步编译
gcc hello.c -o demo
1.3.3 找找程序所依赖的动态库
Linux平台下,ldd可执行程序,如:ldd hello
Windows平台下,需要相应的软件(Depends.exe)
数据类型
2.1 常量与变量
2.1.1关键字
C的关键字共有32个
2.1.2 数据类型
数据类型的作用:编译器预算对象分配内存空间的大小.
数据类型
2.1.3 常量
常量:
格式:
2.1.4 变量
声明变量不需要建立储存空间
定义变量需要建立储存空间
#include
int main()
{
//extern 关键字只做声明,不能做任何定义
//声明一个变量a,a在这里没有建立存储空间
extern int a;
a = 10; //err, 没有空间,就不可以赋值
int b = 10; //定义一个变量b,b的类型为int,b赋值为10
return 0;
}
2.1.5 使用示例
#include
#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);
return 0;
}
2.2 进制
十进制 以正常数字1-9开头,如123
八进制 以数字0开头,如0123
十六进制 以0x开头,如0x123
二进制 C语言不能直接书写二进制数
#include
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);// %x 或 %X
return 0;
}
术语 含义
bit(比特) 一个二进制代表一位,一个位只能表示0或1两种状态。数据传输是习惯以“位”(bit)为单位。
Byte(字节) 一个字节为8个二进制,称为8位,计算机中存储的最小单位是字节。数据存储是习惯以“字节”(Byte)为单位。
WORD(双字节) 2个字节,16位
DWORD 两个WORD,4个字节,32位
1b 1bit,1位
1B 1Byte,1字节,8位
1k,1K 1024
1M(1兆) 1024k, 1024*1024
1G 1024M
2.3 计算机内存数值储存方式
2.3.1 原码
一个数的原码(原始二进制码)有以下特点
原码表示法简单易懂,但是原码不便于加减运算
2.3.2 反码
2.3.3 补码
在计算机系统中,数值一律用补码来存储
补码特点:
2.3.4 补码的意义
示例:计算9-6的结果
以原码方式相加:
十进制数 原码
9 0000 1001
-6 1000 0110
计算结果为 1000 1111( -15),不正确
以补码方式相加:
十进制数 补码
9 0000 1001
-6 1111 1010
计算结果为 1 0000 0011(最高位的1溢出,剩余8位二进制表示是3) 正确
在计算机系统中,数值一律用补码来存储,主要原因:
2.4 sizeof 关键字
sizeof 不是函数,所以不需要包含任何头未见,他的功能是计算一个数据类型的大小,单位为字节
sizeof 的返回值为 size_t
size_t 类型在32位操作系统下湿unsigned int 是一个无符号的整数
#include
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;
}
格式:
注意:根据32位操作系统获取的数据类型大小
2.5 整形
2.5.1 整型变量的输出
#include
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;
}
2.5.2 整型变量输入
#include
int main()
{
int a;
printf("请输入a的值:");
//不要加“\n”
scanf("%d", &a);
printf("a = %d\n", a); //打印a的值
return 0;
}
2.5.3 short, int, long, long long
数据类型 占用空间
short(短整型) 2字节
int(整型) 4字节
long(长整形) Windows为4字节,Linux为4字节(32位),8字节(64位)
long long(长长整形) 8字节
注意:
2.5.4 有符号和无符号数区别
有符号数
有符号数是最高位为符号位,0代表正数,1代表负数
定义: signed int a = -1089474374; //定义有符号整型变量a
无符号数
无符号数最高为不是符号位,而是数的一部分,无符号数不可能是负数.
定义:unsigned int a = 3236958022; //定义无符号整型变量a
当写程序要处理一个不可能出现负值的时候,一般用无符号数,这样可以增大数的表达最大值.
2.6 字符型: char
2.6.1 字符变量的定义和输出
字符型变量用于存储一个单一字符,在C语言中用 char 表示,其中每个字符变量都会占用 1 个字节。在给字符型变量赋值时,需要用一对英文半角格式的单引号(’ ')把字符括起来。
#include
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;
}
2.6.2 自读变量的输入
#include
int main()
{
char ch;
printf("请输入ch的值:");
//不要加“\n”
scanf("%c", &ch);
printf("ch = %c\n", ch); //打印ch的字符
return 0;
}
2.6.3 转义字符
转义字符 含义 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进制
2.6.4 数值溢出
当超过一个数据类型能够存放最大的范围时,数值会溢出.
最高位溢出和符号位溢出的区别:符号位溢出会导致数的正负发生改变,最高位的溢出会导致最高位丢失
2.7 实型(浮点型): float double
实型变量也可以成为浮点型变量,浮点型变量是用来储存小数数值的.在C语言中,浮点型变量分为两种:单精度浮点型(float) 双精度浮点型(double)double类型变量所表示的浮点数比float型变量表示的更精确.
数据类型 占用空间 有效数字范围
float 4字节 7位有效数字
double 8字节 15~16位有效数字
不以 f 结尾的常量是double类型,以f结尾的常量是float类型.
3.运算符与表达式
3.1 常用运算符分类
运算符类型 作用
算术运算符 用于处理四则运算
赋值运算符 用于将表达式的值赋给变量
比较运算符 用于表达式的比较,并返回一个真值或假值
逻辑运算符 用于根据表达式的值返回真值或假值
位运算符 用于处理数据的位运算
sizeof运算符 用于求字节数长度
3.2算术运算符
运算符 术语 示例 结果
正号 +3 3
负号 -3 -3
加 10 + 5 15
减 10 - 5 5
乘 10 * 5 50
/ 除 10 / 5 2
% 取模(取余) 10 % 3 1
++ 前自增 a=2; b=++a; a=3; b=3;
++ 后自增 a=2; b=a++; a=3; b=2;
– 前自减 a=2; b=–a; a=1; b=1;
– 后自减 a=2; b=a–; a=1; b=2;
3.3 赋值运算符
运算符 术语 示例 结果
= 赋值 a=2; b=3; a=2; b=3;
+= 加等于 a=0; a+=2; a=2;
-= 减等于 a=5; a-=3; a=2;
= 乘等于 a=2; a=2; a=4;
/= 除等于 a=4; a/=2; a=2;
%= 模等于 a=3; a%2; a=1;
3.4 比较运算符
C 语言的比较运算中, "真"用数字 1 表示,"假"用数字 0 表示.
运算符 术语 示例 结果
== 相等于 4 == 3 0
!= 不等于 4 != 3 1
< 小于 4 < 3 0
大于 4 > 3 1
<= 小于等于 4 <= 3 0
= 大于等于 4 >= 1 1
3.5 逻辑运算符
运算符 术语 示例 结果
! 非 !a 如果a为假,则!a为真;如果a为真,则!a为假。
&& 与 a && b 如果a和b都为真,则结果为真,否则为假。
|| 或 a || b 如果a和b有一个为真,则结果为真,二者都为假时,结果为假。
3.6 运算符优先级
优先级 运算符 名称或含义 使用形式 结合方向 说明
1 [] 数组下标 数组名[常量表达式] 左到右 –
() 圆括号 (表达式)/函数名(形参表) –
. 成员选择(对象) 对象.成员名 –
-> 成员选择(指针) 对象指针->成员名 –
按位取反运算符 ~表达式
++ 自增运算符 ++变量名/变量名++
– 自减运算符 --变量名/变量名–
取值运算符 *指针变量
& 取地址运算符 &变量名
! 逻辑非运算符 !表达式
(类型) 强制类型转换 (数据类型)表达式 –
sizeof 长度运算符 sizeof(表达式) –
3 / 除 表达式/表达式 左到右 双目运算符
乘 表达式*表达式
% 余数(取模) 整型表达式%整型表达式
4 + 加 表达式+表达式 左到右 双目运算符
减 表达式-表达式
5 << 左移 变量<<表达式 左到右 双目运算符
右移 变量>>表达式
6 > 大于 表达式>表达式 左到右 双目运算符
= 大于等于 表达式>=表达式
< 小于 表达式<表达式
<= 小于等于 表达式<=表达式
7 == 等于 表达式==表达式 左到右 双目运算符
!= 不等于 表达式!= 表达式
8 & 按位与 表达式&表达式 左到右 双目运算符
9 ^ 按位异或 表达式^表达式 左到右 双目运算符
10 | 按位或 表达式|表达式 左到右 双目运算符
11 && 逻辑与 表达式&&表达式 左到右 双目运算符
12 || 逻辑或 表达式||表达式 左到右 双目运算符
13 ?: 条件运算符 表达式1?表达式2: 表达式3 右到左 三目运算符
14 = 赋值运算符 变量=表达式 右到左 –
/= 除后赋值 变量/=表达式 –
= 乘后赋值 变量=表达式 –
%= 取模后赋值 变量%=表达式 –
+= 加后赋值 变量+=表达式 –
-= 减后赋值 变量-=表达式 –
<<= 左移后赋值 变量<<=表达式 –
= 右移后赋值 变量>>=表达式 –
&= 按位与后赋值 变量&=表达式 –
^= 按位异或后赋值 变量^=表达式 –
|= 按位或后赋值 变量|=表达式 –
15 , 逗号运算符 表达式,表达式,… 左到右 –
3.7类型转换
数据有不同的类型,不同类型数据之间进行混合运算是必然涉及到类型的转换.
转换类型有两种方式:
类型转换的原则:占用内存字节数少的类型向占用内存字节数多的类型转换,以保证精度不降低.
3.7.1 隐式转换
#include
int main()
{
int num = 5;
printf("s1=%d\n", num / 2);
printf("s2=%lf\n", num / 2.0);
return 0;
}
3.7.2 强制转换
强制类型转换指的是适应强制类型转换运算符,将一个变量或表达式转化成所需的类型,基本语法: (类型说明符) (表达式)
#include
int main()
{
float x = 0;
int i = 0;
x = 3.6f;
i = x; //x为实型, i为整型,直接赋值会有警告
i = (int)x; //使用强制类型转换
printf("x=%f, i=%d\n", x, i);
return 0;
}
4.1 概述
C 语言支持最基本的三种程序运行结构:顺序结构 选择结构 循环结构.
4.2 选择结构
4.2.1 if 语句
#include
int main()
{
int a = 1;
int b = 2;
if (a > b)
{
printf("%d\n", a);
}
return 0;
}
4.2.2 if … else 语句
#include
int main(void)
{
int a =1;
int b =2;
if(a>b)
{
printf("%d\n",a)
}
else
{
printf("%d\n",b)
}
return 0
}
4.2.3 if … else if … else
#include
int main()
{
unsigned int a;
scanf("%u", &a);
if (a < 10)
{
printf("个位\n");
}
else if (a < 100)
{
printf("十位\n");
}
else if (a < 1000)
{
printf("百位\n");
}
else
{
printf("很大\n");
}
return 0;
}
4.2.4 三目运算符
#include
int main()
{
int a = 10;
int b = 20;
int c;
if (a > b)
{
c = a;
}
else
{
c = b;
}
printf("c1 = %d\n", c);
a = 1;
b = 2;
c = ( a > b ? a : b );
printf("c2 = %d\n", c);
return 0;
}
4.2.5 switch
#include
int main()
{
char c;
c = getchar();
switch (c) //参数只能是整型变量
{
case '1':
printf("OK\n");
break;//switch遇到break就中断了
case '2':
printf("not OK\n");
break;
default://如果上面的条件都不满足,那么执行default
printf("are u ok?\n");
}
return 0;
}
注意:
if条件语句执行效率差, switch 条件语句执行效率高,但是 if 可以判断一个区间 switch用来判断一个值, 三目运算符结构简单明了.
4.3 循环结构
4.3.1 while 语句
#include
int main()
{
int a = 20;
while (a > 10)
{
scanf("%d", &a);
printf("a = %d\n", a);
}
return 0;
}
while 语句一般用于不确定循环次数的情况下
4.3.2 do … while 语句
#include
int main()
{
int a = 1;
do
{
a++;
printf("a = %d\n", a);
} while (a < 10);
return 0;
}
do … while 语句无论条件是否满足.循环总执行一次
4.3.3 for 语句
#include
int main()
{
int i;
int sum = 0;
for (i = 0; i <= 100; i++)
{
sum += i;
}
printf("sum = %d\n", sum);
return 0;
}
最常使用的循环语句,常用语已知循环出口的情况
4.4 跳转语句 break continue goto
4.4.1 break 语句
在 switch 条件语句和循环语句中可以使用 break 语句:
break 不能直接用于if 的,但是如果在for 里面,是可以用的,就是如果达到条件,就退出for
#include
int main()
{
int i = 0;
while (1)
{
i++;
printf("i = %d\n", i);
if (i == 10)
{
break; //跳出while循环
}
}
int flag = 0;
int m = 0;
int n = 0;
for (m = 0; m < 10; m++)
{
for (n = 0; n < 10; n++)
{
if (n == 5)
{
flag = 1;
break; //跳出for (n = 0; n < 10; n++)
}
}
if (flag == 1)
{
break; //跳出for (m = 0; m < 10; m++)
}
}
return 0;
}
4.3.2 continue 语句
再循环中,如果希望立即终止本次循环,并执行下一次循环,此时就需要食用 continue 语句.
#include
int main()
{
int sum = 0; //定义变量sum
for (int i = 1; i <= 100; i++)
{
if (i % 2 == 0) //如果i是一个偶数,执行if语句中的代码
{
continue; //结束本次循环
}
sum += i; //实现sum和i的累加
}
printf("sum = %d\n", sum);
return 0;
}
注意: 使用 continue 时要考虑到循环变量自增或自减,避免死循环
4.3.3 goto 语句 (无条件跳转, 尽量少用)
#include
int main()
{
goto End; //无条件跳转到End的标识
printf("aaaaaaaaa\n");
End:
printf("bbbbbbbb\n");
return 0;
}
5 .数组和字符串
5.1 概述
在程序设计中,为了方便处理数据,把具有相同类型的若干变量按有序形式组织起来称为数组.
数组就是在内存中连续的相同类型的变量空间,同一个数组所有的成员都是相同的数据类型,同时所有的成员在内存中的地址是连续的.
数组属于狗仔数据类型:
通常情况下,数组元素下标的个数也称为维数.根据维数的不同,可将数组分为一维数组,二维数组,三维数组等.通常情况下,我们将二位及以上的数组称为多维数组.
5.2 一维数组
5.2.1 一维数组的定义和使用
数组名符合标识符的书写规定
数组名不能与其他变量名相同
方括号" [ ] "中常量表达时表示数组元素的个数
定义数组时" [ ] "内嘴还是常量,使用数组时 " [ ] "既可以是常量也可以是变量
#include
int main()
{
int a[10];//定义了一个数组,名字叫a,有10个成员,每个成员都是int类型
//a[0]…… a[9],没有a[10]
//没有a这个变量,a是数组的名字,但不是变量名,它是常量
a[0] = 0;
//……
a[9] = 9;
int i = 0;
for (i = 0; i < 10; i++)
{
a[i] = i; //给数组赋值
}
//遍历数组,并输出每个成员的值
for (i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
5.2.2 一位数组的初始化
在定义数组的同时进行赋值,称为初始化.全局数组若不初始化,便一起将其初始化为零.局部数组若不初始化,内容为随机值.
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//定义一个数组,同时初始化所有成员变量
int a[10] = { 1, 2, 3 };//初始化前三个成员,后面所有元素都设置为0
int a[10] = { 0 };//所有的成员都设置为0
//[]中不定义元素个数,定义时必须初始化
int a[] = { 1, 2, 3, 4, 5 };//定义了一个数组,有5个成员
求出数组元素个数:
int (size_t) unsigned int 个数 = sizeof(数组名)/sizeof(数组元素 | 数组数据类型)
5.2.3 数组名
数组名是一个地址的常量,代表数组中首元素的地址.
#include
int main()
{
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//定义一个数组,同时初始化所有成员变量
printf("a = %p\n", a);
printf("&a[0] = %p\n", &a[0]);
int n = sizeof(a); //数组占用内存的大小,10个int类型,10 * 4 = 40
int n0 = sizeof(a[0]);//数组第0个元素占用内存大小,第0个元素为int,4
int i = 0;
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
5.2.3 一维数组应用
一维数组的最值
#include
int main()
{
int a[] = { 1, -2, 3,- 4, 5, -6, 7, -8, -9, 10 };//定义一个数组,同时初始化所有成员变量
int i = 0;
int max = a[0];
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
if (a[i] > max)
{
max = a[i];
}
}
printf("数组中最大值为:%d\n", max);
return 0;
}
一维数组的逆序
#include
int main()
{
int a[] = { 1, -2, 3,- 4, 5, -6, 7, -8, -9, 10 };//定义一个数组,同时初始化所有成员变量
int i = 0;
int j = sizeof(a) / sizeof(a[0]) -1;
int tmp;
while (i < j)
{
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
i++;
j--;
}
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
冒泡排序
#include
int main()
{
int a[] = { 1, -2, 3,- 4, 5, -6, 7, -8, -9, 10 };//定义一个数组,同时初始化所有成员变量
int i = 0;
int j = 0;
int n = sizeof(a) / sizeof(a[0]);
int tmp;
//1、流程
//2、试数
for (i = 0; i < n-1; i++)
{
for (j = 0; j < n - i -1 ; j++)//内循环的目的是比较相邻的元素,把大的放到后面
{
if (a[j] > a[j + 1])
{
tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
}
}
}
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
5.3 二维数组
5.3.1 二维数组的定义和使用
二维数组定义的一般形式是:
类型说明符 数组名 [常量表达式1][常量表达式2]
其中常量表达式1表示第一维下标的长度,常量表达式2表示第二维下标的长度.
命名规则同一维数组
int a[3][4]定义一个 3 行 4 列数组,数组名为 a 其元素类型为整形,该数组的元素个数为 3 * 4 个,二维数组 a 是按行进行存放的,先存放 a[0]行,在存放 a[1]行,并且每行有四个元素,也是一次存放的.
二维数组在概念上是二维的: 其下标在两个方向上变化,对其访问一般需要两个下标.
在内存中并不存在二位数组,二位数组实际的硬件存储器是连续编址的,也就是说内存中只有一维数组,即放完一行之后顺次放入第二行,和一维数组存放方式是一样的.
#include
int main()
{
//定义了一个二维数组,名字叫a
//由3个一维数组组成,这个一维数组是int [4]
//这3个一维数组的数组名分别为a[0],a[1],a[2]
int a[3][4];
a[0][0] = 0;
//……
a[2][3] = 12;
//给数组每个元素赋值
int i = 0;
int j = 0;
int num = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
a[i][j] = num++;
}
}
//遍历数组,并输出每个成员的值
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d, ", a[i][j]);
}
printf("\n");
}
return 0;
}
5.3.2 二维数组的初始化
//分段赋值 int a[3][4] = {{ 1, 2, 3, 4 },{ 5, 6, 7, 8, },{ 9, 10, 11, 12 }};
int a[3][4] =
{
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8, },
{ 9, 10, 11, 12 }
};
//连续赋值
int a[3][4] = { 1, 2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12 };
//可以只给部分元素赋初值,未初始化则为0
int a[3][4] = { 1, 2, 3, 4 };
//所有的成员都设置为0
int a[3][4] = {0};
//[]中不定义元素个数,定义时必须初始化
int a[][4] = { 1, 2, 3, 4, 5, 6, 7, 8};
5.3.3 数组名
数组名是一个地址的常量,代表数组中首元素的地址
#include
int main()
{
//定义了一个二维数组,名字叫a
//二维数组是本质上还是一维数组,此一维数组有3个元素
//每个元素又是一个一维数组int[4]
int a[3][4] = { 1, 2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12 };
//数组名为数组首元素地址,二维数组的第0个元素为一维数组
//第0个一维数组的数组名为a[0]
printf("a = %p\n", a);
printf("a[0] = %p\n", a[0]);
//测二维数组所占内存空间,有3个一维数组,每个一维数组的空间为4*4
//sizeof(a) = 3 * 4 * 4 = 48
printf("sizeof(a) = %d\n", sizeof(a));
//测第0个元素所占内存空间,a[0]为第0个一维数组int[4]的数组名,4*4=16
printf("sizeof(a[0]) = %d\n", sizeof(a[0]) );
//测第0行0列元素所占内存空间,第0行0列元素为一个int类型,4字节
printf("sizeof(a[0][0]) = %d\n", sizeof(a[0][0]));
//求二维数组行数
printf("i = %d\n", sizeof(a) / sizeof(a[0]));
// 求二维数组列数
printf("j = %d\n", sizeof(a[0]) / sizeof(a[0][0]));
//求二维数组行*列总数
printf("n = %d\n", sizeof(a) / sizeof(a[0][0]));
return 0;
}
5.4 多维数组(了解)
多维数组的定义与二维数组类似.
#include
int main()
{
//int a[3][4][5] ;//定义了一个三维数组,有3个二维数组int[4][5]
int a[3][4][5] = { { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, { 0 }, { 0 } }, { { 0 }, { 0 }, { 0 }, { 0 } }, { { 0 }, { 0 }, { 0 }, { 0 } } };
int i, j, k;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
for (k = 0; k < 5; k++)
{
//添加访问元素代码
printf("%d, ", a[i][j][k]);
}
printf("\n");
}
}
return 0;
}
5.5 字符数组与字符串
5.5.1 字符数组与字符串的区别
C 语言中没有字符串这种数据类型,可以通过char 的数组来代替
字符串一定是一个 char 的数组, 但 char 的数组未必是字符串
数字0(和字符 ‘\0’ 等价)结尾的 char 数组就是一个字符串, 但如果 char数组没有数字 0 结尾,那么就不是一个字符串, 只是普通字符数组, 所以字符串是一种特殊的 char 的数组.
#include
int main()
{
char c1[] = { ‘c’, ’ ', ‘p’, ‘r’, ‘o’, ‘g’ }; //普通字符数组
printf(“c1 = %s\n”, c1); //乱码,因为没有’\0’结束符
//以‘\0’(‘\0’就是数字0)结尾的字符数组是字符串
char c2[] = { 'c', ' ', 'p', 'r', 'o', 'g', '\0'};
printf("c2 = %s\n", c2);
//字符串处理以‘\0’(数字0)作为结束符,后面的'h', 'l', 'l', 'e', 'o'不会输出
char c3[] = { 'c', ' ', 'p', 'r', 'o', 'g', '\0', 'h', 'l', 'l', 'e', 'o', '\0'};
printf("c3 = %s\n", c3);
return 0;
}
5.5.2 字符串的初始化
#include
// C语言没有字符串类型,通过字符数组模拟
// C语言字符串,以字符‘\0’, 数字0
int main()
{
//不指定长度, 没有0结束符,有多少个元素就有多长
char buf[] = { 'a', 'b', 'c' };
printf("buf = %s\n", buf); //乱码
//指定长度,后面没有赋值的元素,自动补0
char buf2[100] = { 'a', 'b', 'c' };
printf("buf2 = %s\n", buf2);
//所有元素赋值为0
char buf3[100] = { 0 };
//char buf4[2] = { '1', '2', '3' };//数组越界
char buf5[50] = { '1', 'a', 'b', '0', '7' };
printf("buf5 = %s\n", buf5);
char buf6[50] = { '1', 'a', 'b', 0, '7' };
printf("buf6 = %s\n", buf6);
char buf7[50] = { '1', 'a', 'b', '\0', '7' };
printf("buf7 = %s\n", buf7);
//使用字符串初始化,编译器自动在后面补0,常用
char buf8[] = "agjdslgjlsdjg";
//'\0'后面最好不要连着数字,有可能几个数字连起来刚好是一个转义字符
//'\ddd'八进制字义字符,'\xdd'十六进制转移字符
// \012相当于\n
char str[] = "\012abc";
printf("str == %s\n", str);
return 0;
}
5.5.3 字符串的输入输出
由于字符串采用了 ‘\0’ 标志, 字符串的输入输出将变得简单方便.
#include
int main()
{
char str[100];
printf("input string1 : \n");
scanf("%s", str);//scanf(“%s”,str)默认以空格分隔
printf("output:%s\n", str);
return 0;
}
5.5.4 字符串追加
#include
int main()
{
char str1[] = "abcdef";
char str2[] = "123456";
char dst[100];
int i = 0;
while (str1[i] != 0)
{
dst[i] = str1[i];
i++;
}
int j = 0;
while (str2[j] != 0)
{
dst[i + j] = str2[j];
j++;
}
dst[i + j] = 0; //字符串结束符
printf("dst = %s\n", dst);
return 0;
}
5.5.5 字符串处理函数
gets()
#include
char *gets(char *s);
功能:从标准输入读入字符,并保存到s指定的内存空间,直到出现换行符或读到文件结尾为止。
参数:
s:字符串首地址
返回值:
成功:读入的字符串
失败:NULL
注意: 由于 scanf() 和 gets() 无法知道字符串的大小,必须遇到换行符或督导文件结尾为止才接收输入,因此容易导致自负数组越界的情况.
fgets()
#include
char *fgets(char *s, int size, FILE *stream);
功能:从stream指定的文件内读入字符,保存到s所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 ‘\0’ 作为字符串结束。
参数:
s:字符串
size:指定最大读取字符串的长度(size - 1)
stream:文件指针,如果读键盘输入的字符串,固定写为stdin
返回值:
成功:成功读取的字符串
读到文件尾或出错: NULL
fgets()在读取一个用户通过键盘输入的字符串的时候,同时把用户输入的回车也做为字符串的一部分。通过scanf和gets输入一个字符串的时候,不包含结尾的“\n”,但通过fgets结尾多了“\n”。fgets()函数是安全的,不存在缓冲区溢出的问题。
puts()
#include
int puts(const char *s);
功能:标准设备输出s字符串,在输出完成后自动输出一个’\n’。
参数:
s:字符串首地址
返回值:
成功:非负数
失败:-1
fputs()
#include
int fputs(const char * str, FILE * stream);
功能:将str所指定的字符串写入到stream指定的文件中, 字符串结束符 ‘\0’ 不写入文件。
参数:
str:字符串
stream:文件指针,如果把字符串输出到屏幕,固定写为stdout
返回值:
成功:0
失败:-1
strlen()
#include
size_t strlen(const char *s);
功能:计算指定指定字符串s的长度,不包含字符串结束符‘\0’
参数:
s:字符串首地址
返回值:字符串s的长度,size_t为unsigned int类型
strcpy()
#include
char *strcpy(char *dest, const char *src);
功能:把src所指向的字符串复制到dest所指向的空间中,’\0’也会拷贝过去
参数:
dest:目的字符串首地址
src:源字符首地址
返回值:
成功:返回dest字符串的首地址
失败:NULL
注意:如果参数 dest 所致的内存空间不够大, 可能会造成缓冲溢出的错误情况.
strncpy()
#include
char *strcpy(char *dest, const char *src);
功能:把src所指向的字符串复制到dest所指向的空间中,’\0’也会拷贝过去
参数:
dest:目的字符串首地址
src:源字符首地址
返回值:
成功:返回dest字符串的首地址
失败:NULL
char dest[20] ;
char src[] = “hello world”;
strncpy(dest, src, 5);
printf("%s\n", dest);
dest[5] = '\0';
printf("%s\n", dest);
strcat()
#include
char *strcat(char *dest, const char *src);
功能:将src字符串连接到dest的尾部,‘\0’也会追加过去
参数:
dest:目的字符串首地址
src:源字符首地址
返回值:
成功:返回dest字符串的首地址
失败:NULL
char str[20] = "123";
char *src = "hello world";
printf("%s\n", strcat(str, src));
strncat()
#include
char *strncat(char *dest, const char *src, size_t n);
功能:将src字符串前n个字符连接到dest的尾部,‘\0’也会追加过去
参数:
dest:目的字符串首地址
src:源字符首地址
n:指定需要追加字符串个数
返回值:
成功:返回dest字符串的首地址
失败:NULL
char str[20] = "123";
char *src = "hello world";
printf("%s\n", strncat(str, src, 5));
strcmp()
#include
int strcmp(const char *s1, const char *s2);
功能:比较 s1 和 s2 的大小,比较的是字符ASCII码大小。
参数:
s1:字符串1首地址
s2:字符串2首地址
返回值:
相等:0
大于:>0
小于:<0
char *str1 = “hello world”;
char *str2 = “hello mike”;
if (strcmp(str1, str2) == 0)
{
printf("str1==str2\n");
}
else if (strcmp(str1, str2) > 0)
{
printf("str1>str2\n");
}
else
{
printf("str1
strncmp()
#include
int strncmp(const char *s1, const char *s2, size_t n);
功能:比较 s1 和 s2 前n个字符的大小,比较的是字符ASCII码大小。
参数:
s1:字符串1首地址
s2:字符串2首地址
n:指定比较字符串的数量
返回值:
相等:0
大于: > 0
小于: < 0
char *str1 = “hello world”;
char *str2 = “hello mike”;
if (strncmp(str1, str2, 5) == 0)
{
printf("str1==str2\n");
}
else if (strcmp(str1, "hello world") > 0)
{
printf("str1>str2\n");
}
else
{
printf("str1
sprintf()
#include
int sprintf(char *_CRT_SECURE_NO_WARNINGS, const char *format, …);
功能:根据参数format字符串来转换并格式化数据,然后将结果输出到str指定的空间中,直到出现字符串结束符 ‘\0’ 为止。
参数:
str:字符串首地址
format:字符串格式,用法和printf()一样
返回值:
成功:实际格式化的字符个数
失败: - 1
char dst[100] = { 0 };
int a = 10;
char src[] = "hello world";
printf("a = %d, src = %s", a, src);
printf("\n");
int len = sprintf(dst, "a = %d, src = %s", a, src);
printf("dst = \" %s\"\n", dst);
printf("len = %d\n", len);
sscanf()
#include
int sscanf(const char *str, const char *format, …);
功能:从str指定的字符串读取数据,并根据参数format字符串来转换并格式化数据。
参数:
str:指定的字符串首地址
format:字符串格式,用法和scanf()一样
返回值:
成功:参数数目,成功转换的值的个数
失败: - 1
char src[] = "a=10, b=20";
int a;
int b;
sscanf(src, "a=%d, b=%d", &a, &b);
printf("a:%d, b:%d\n", a, b);
strchr()
#include
char *strchr(const char *s, int c);
功能:在字符串s中查找字母c出现的位置
参数:
s:字符串首地址
c:匹配字母(字符)
返回值:
成功:返回第一次出现的c地址
失败:NULL
char src[] = "ddda123abcd";
char *p = strchr(src, 'a');
printf("p = %s\n", p);
strstr()
#include
char *strstr(const char *haystack, const char *needle);
功能:在字符串haystack中查找字符串needle出现的位置
参数:
haystack:源字符串首地址
needle:匹配字符串首地址
返回值:
成功:返回第一次出现的needle地址
失败:NULL
char src[] = "ddddabcd123abcd333abcd";
char *p = strstr(src, "abcd");
printf("p = %s\n", p);
strtok()
#include
char *strtok(char *str, const char *delim);
功能:来将字符串分割成一个个片段。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时, 则会将该字符改为\0 字符,当连续出现多个时只替换第一个为\0。
参数:
str:指向欲分割的字符串
delim:为分割字符串中包含的所有字符
返回值:
成功:分割后字符串首地址
失败:NULL
- 在第一次调用时: strtok ()必须给与参数 s 字符串
- 往后调用则见参数 s 设置成 NULL , 每次调用成功则返回指向被分割出片段的指针
char a[100] = "adc*fvcv*ebcy*hghbdfg*casdert";
char *s = strtok(a, "*");//将"*"分割的子串取出
while (s != NULL)
{
printf("%s\n", s);
s = strtok(NULL, "*");
}
atof(): 把一个小数形式的字符串转化为一个浮点数
atol(): 将有一个字符串转换为 long 类型
char str1[] = “-10”;
int num1 = atoi(str1);
printf(“num1 = %d\n”, num1);
char str2[] = "0.123";
double num2 = atof(str2);
printf("num2 = %lf\n", num2);