Linux c语言
统一声明:
博客转载 声 明 : 本博客部分内容来源于网络、书籍、及各类手册。
内容宗旨为方便查询、总结备份、开源分享。
部分转载内容均有注明出处,如有侵权请联系博客告知并删除,谢谢!
百度云盘提取码:统一提取码:ziyu
C语言源码下载地址:https://download.csdn.net/download/qq_43498137/22171766
可见本文末尾 代码案例详情!
个人网站入口:http://www.baiziqing.cn/
一、Linux基础
1.1、Linux环境搭建
1.4.1、Linux环境搭建
如果没有Linux环境先安装虚拟机和Ubuntu
转载 最新超详细VMware虚拟机下载与安装 链接:https://blog.csdn.net/qq_40950957/article/details/80467513
转载 VMware虚拟机安装Linux系统(详解版) 链接:http://c.biancheng.net/view/714.html
Ubuntu系统 下载 链接:https://cn.ubuntu.com/download
Ubuntu低版本可能不能上网下载,可以推荐我配置好的 Ubuntu 64_20.04 可上网高版本,直接解压打开使用VM打开即可。
Ubuntu 64_20.04 阿里云链接:https://www.aliyundrive.com/s/DWUDBP5KZsU
Ubuntu 64_20.04 百度云链接:https://pan.baidu.com/s/1OEYYSHQ1eTVJE-iHjWb7WQ
1.2、Linux基础
打开ubuntu
普通用户:farsight 密码:1
超级用户:root 密码:1
/:根目录
~:家目录 == /home/farsight
$:命令提示符 普通用户 #超级用户
打开终端:
直接点击图标 terminal
快捷键:ctl+alt+t //打开新终端
右键:open terminal //再打开
ctrl+shift+n //打开
ctrl+shift+t //并列打开,打开一个标签
调节字体:ctrl+shift+‘+’ //调大字体
ctrl+‘-’ //调小字体
1.3、终端命令
终端命令:
pwd:显示当前所在的路径
ls :查看当前目录下的文件
ls -a:显示隐藏文件
ls -l:显示目录的详细信息
drwxrwxr-x 11 farsight farsight 4096 Jul 31 2020 desktop
d:目录文件,文件夹
rwx rwx r-x:文件权限
11 :文件的硬链接数
farsight:用户组名
farsight:用户名
4096:文件大小 以 字节为单位
Jul 31 2020:文件创建时间
desktop:文件名
clear :清屏操作 快捷键:ctl+‘l’
mkdir+文件名 :创建一个新的目录文件
mkdir -p:递归创建
cd :跳转
. :当前目录
.. :上级目录
touch:创建一个普通文件,一般加后缀
更新时间戳
mv 文件名1 文件名2 //将文件重命名为文件名2
mv 文件名1 路径 //移动文件到路径下
文件路径不同,起到移动的作用,文件名在移动后的路径下没有,文件路径相同,重命名
rm:删除普通文件
-r:删除目录文件
mdir:安全删除空文件,非空时警告
man 手册
man 1:普通命令
man 2:系统调用
man 3:库函数
绝对路径:从根目录出发,一直到指定的目录
相对路径:相对于当前位置
gedit test//类似于文本文档
cat:查看文件内容
-b:加行号显示
-s:合并多空行
cp 文件名1 文件名2 //复制普通文件1到文件2
-r 文件名1 文件名2//复制目录文件1到目录文件2
练习:
1、用相对路径的方式,切换到上一级的上一级目录
cd ./../../ cd .. cd ..
2、用绝对路径的方式,切换到根目录下的usr下的include目录
cd /usr/include
3、在家目录下创建一个school,再在该目录下创建两个目录 class1 class2
mkdir -p school/class1 school/class2
4、在class1中创建两个普通的文件
touch day1.txt test.txt
二、vi编辑器
2.1、vi编辑器
vi编辑器:
刚进入时在命令行模式下:
进入插入模式(进行编辑):
i o a I O A
i:从光标的当前位置开始编辑
a:从光标的后一个位置开始编辑
o:从光标的后一行位置开始编辑
I:从光标当行 第一个位置开始编辑
O:从光标当行 前一行位置开始编辑
A:从光标当行 最后一个位置开始编辑
回到命令行模式:Esc
进入底行模式:shift+“:”
:w //进行保存
:q //退出
:wq //保存并退出
:x //保存并退出
:q!//强制退出
:wq!//强制保存并退出
命令行模式下:
dd //删除光标所在行
ndd //删除光标向下的n行
yy //复制光标所在行
nyy //复制光标向下的n行
p //粘贴到光标所在的下一行或下一个
P //(大写P)粘贴到光标所在的前一行或前一个
r //改变光标所在的字符,只改变一次
R //改变光标所在的字符,Esc退出
x //剪切或删除光标所在的一个字符
X //剪切或删除光标所在的前一个字符
s //删除光标所在的字符,并进入插入模式
S //删除光标所在的行,并进入插入模式
u //撤销
ctrl+r //反向撤销
底行模式:
:s/str1/str2 //将str1替换成str2 替换光标所在行的第一个
:s/str1/str2/g //将str1替换成str2 替换光标所在行的所有
:%s/str1/str2/g //将str1替换成str2 替换全文
:%s/str1/str2 //将str1替换成str2 替换全文第一个
:n,ms/str1/str2 //将str1替换成str2 替换n到m行的第一个
:n,ms/str1/str2/gc //将str1替换成str2 替换n到m行的第一个
:n,my //复制n到m行
:n,md //删除n到m行
:set number //显示行号
:set nonumber //隐藏行号
vi/vim 文件不存在时会自动创建
2.2、GCC编译工具
GCC编译工具:
gcc test.c //默认生成a.out可执行文件
gcc test.c -o test //将生成可执行文件命名为test
gcc -o test.c test
编译运行的四个步骤:预处理、编译、汇编、链接
预处理:处理头文件、宏定义等,不进行错误检查
gcc -E test.c -o test.i
编译:将预处理的文件进行处理,检查错误,生成汇编文件
gcc -S test.i -o test.s
汇编:将汇编文件编译生成机器语言 二进制文件
gcc -c test.s -o test.o
链接:生成可执行文件
gcc test.o -o test
2.3、存储器
存储器:用来存放程序和数据。
程序和数据在计算机中都是以二进制的形式存放存储器中
存储容量的大小是以字节为单位度量,经常用KB、MB、GB、TB
1KB = 1024B 1GB = 1024KB 1TB = 1024G
(1)存储器分为内存储器(主存储器)和外存储器(辅助存储器)
内存 在计算机中,直接和运算器、控制器交换信息
容量小、存取速度快
外存 间接和cpu联系,存放一些必须使用但又不急于使用的程序和数据
程序必须调入内存中才能执行
程序:系统可以识别的指令。存储在 磁盘上 ,执行时 从磁盘 到内存 再到寄存器 最后被cpu执行
三、C语言基础
3.1、基本c语言程序结构
#include<stdio.h> //预编译命令
int main(void)//主函数名 int 函数返回类型
{
return 0;//返回值 必须和函数数据类型匹配
}
return 0;//默认 正常结束
return -1;// 异常结束
数值数据:
数制的数:按位权展开的多项式的和
3.2、进制之间的转换
(1)十进制
基数:10 (0 1 2 3 4 5 6 7 8 9)
位权:数字权位的大小
eg:123 = 1*10^2+2*10^1+3*10^0
3 10^0 位权:1
2 10^1 10
1 10^2 100
(2)二进制
一般形式:0b111000
基数:2 (0 1)
位权:101 = 1*2^0+0*2^1+1*2^2 = 5
xx1 : 2^0 位权:1
x0x : 2^1 位权:2
1xx : 2^2 位权:4
1 2 4 8 16 32 64 128 256 512 1024
二进制转十进制:每一位数乘位权 相加
十进制转二进制:a:短除法 b:凑数法
(3)八进制:
一般形式:01101000
基数:8 (0 1 2 3 4 5 6 7 )
位权:1 8 64 512
eg:0101
八进制转十进制:1*8^0+0*8^1+1*8^2+0*8^3 = 65
十进制转八进制:a:短除法 b:凑数法
八进制转二进制:a:一位八进制 转成 三位二进制
eg:0234 0b 010 011 100
b:先转成十进制 再转成二进制
(4)十六进制
一般形式:0x110101
基数:16 (0 1 2 3 4 5 6 7 8 9 A B C D E F)
位权:1 16 256
十六进制转十进制:按位权相加
十六进制转二进制:a:一位十六进制 转成 四位二进制
eg:0x234 0b 0010 0011 0100
二进制转十六进制:四位二进制转成一位十六进制
eg: 0b0001 1001 0100 0x194
二进制:0b
八进制:0
十六进制:0x
位(bit):计算机中存储数据的最小单位
字节(Byte):存储容量的度量单位,数据处理的基本单位
1个字节的存储空间 称为 一个存储单元
1Byte = 8 bit
ubuntu 32位 ----4字节
计算机中非数值数据
printf("hello!\n");
ASCII码:
0 null('\0')
10 '\n'
48 '0'
65 'A'
97 'a'
122 'z'
32 空格
‘A’--->'a' 'A'+32
'9'--->9 '9'-'0' '9'-48
词法符号:程序设计语言中有若干字符组成的有意义的 最小语法单位
3.3、关键字
按作用分类:关键字、标识符、分隔符、运算符、标点符号
关键字:32个
auto:声明自动变量 一般不使用
double:声明双精度的变量或函数
int:声明整型的变量或函数
struct:声明结构体变量或函数
break:跳出当前循环
if:条件语句 肯定分支
else:条件语句 否定分支
long:声明长整型的变量或函数
switch:用于多分支
case:开关语句分支
enum:声明枚举类型
register:声明寄存器变量
typedef:用来给数据类型取别名
char:声明字符型的变量或函数
extern:看成引用
return:子程序中返回语句(可以带参数,也可以不带)
union:声明联合数据类型
const:声明只读变量
float:声明浮点型的变量或函数
short:声明短整型的变量或函数
unsigned:声明无符号类型的变量或函数
continue:结束当前循环,开始下一轮循环
for:一种循环语句
signed:声明有符号类型的变量或函数
void:声明函数无返回值或无参数,声明无类型的指针
default:开关语句的其他分支
goto:无条件的跳转
sizeof:计算数据类型的长度
volatile:声明变量在程序中可以被隐含的改变
do:循环语句中的循环体
while:循环语句中的循环条件
static:声明静态变量
3.4、数据类型
基本数据类型:char、short、int、long、float、double
存储类型(有符号、无符号):signed、unsigned、static、register、extern、const、volatile、auto
语句:if、else、for、while、do、goto、switch、case、default、break、continue、return
构造:union、struct、enum、
求字节:sizeof
取别名:typdef
空类型:void
3.5、标识符
程序员按照命名规则自行定义的词法符号
命名规则:
1、由字母、数字、下划线(_)组成
2、不能和关键字重名
3、只能由字母或下划线开头
标识符的命名方式:
见名知意
骆驼命名法:混合大小写字母构成变量名或函数名
小驼峰:
常用于变量
eg:myFirstName
大驼峰(帕斯卡命名法):
常用于类名、函数名
eg:DataBaseUser
下划线命名法:
eg:print_students_count();
linux下严格区分大小写!
3.6、分格符
空格 ‘ ’ 32
换行 ‘\n’ 10
制表符 '\t' 9
注释:1、/*提示信息,注释一段内容*/
2、//注释一行内容
3、#if 0
中间内容被注释
#else
中间内容正常执行
#endif
#if 1
中间内容正常执行
#else
中间内容被注释
#endif
3.7、运算符
运算符:算数、关系、逻辑、位
根据操作数不同,分为单目运算符、双目运算符、三目运算符(?:)
算术运算符:+ - * / % ++ --
注:i++和++i的区别
关系运算:< > >= <= != ==(判断是否相等)
int a = 3;
int b = 4;
(a>b) 0
(a<b) 1
(a!=b) 1
(a==b) 0
逻辑运算符:&&(与) ||(或) !(非)
逻辑:0 为假,非0 为真
&&:两边为真才为真,只要有一边为假就为假
||:只要有一边为真,就为真
两边为假才为假
!:真假互换
位运算:&(按位与) |(按位或) ~(按位取反) ^(异或) <<(左移) >>(右移)
异或:相异为1 相同为0
左移:右边补0 右移:左边补0
1110 0101 << 2 1001 0100 1110 0101 >> 2 0011 1001
位运算的一般用法:对指定位清0 置1
//位运算的位置从0 开始计数
(1)对指定位清0
eg:对i的第2位清0 i=i & ~(1<<2)
(2)对指定位置1
eg:对i的第5位置1 i=i | (1<<5)
赋值运算符:= += -= *= /= %= ^=
int a = 3;
int b = 4;
a += b ===> a = a+b
a -= b ===> a = a-b
a *= b ===> a = a*b
其他运算符:自增 自减
a++ ==> a=a a+1
++a ==> a+1 a=a
a-- ==> a=a a-1
?: & * [] sizeof()
标点符号:
, ; () {
}
3.8、数据类型
数据类型:
基本数据类型:(在没有写明时,默认有符号)
int 整型:在内存中占4字节
unsigned int范围:0~2^32-1
0000 0000 0000 0000 0000 0000 0000 0000
1111 1111 1111 1111 1111 1111 1111 1111
//10000 0000 0000 0000 0000 0000 0000 0000 -1
signed:(有符号数,将数据的第一位看做符号位,0表示正数,1表示负数)
signed int 范围:-2^31~2^31-1
0000 0000 0000 0000 0000 0000 0000 0000 //+0
0111 1111 1111 1111 1111 1111 1111 1111 //+2^31-1
1000 0000 0000 0000 0000 0000 0000 0000 //-2^31
1111 1111 1111 1111 1111 1111 1111 1111//-(2^31-1)
char字符型:在内存中占1字节(特殊的整型)
字符:用单引号引起来的一个字符(ASCII码) 'a' '1'
unsigned: 无符号 正整数
unsigned char范围:0~255
1111 1111
0000 0000
signed:(有符号数,将数据的第一位看做符号位,0表示正数,1表示负数)
signed char范围:
0 000 0000 //+0
0 111 1111 //+127
1 000 0000 //-128(-0无意义)
1 111 1`在这里插入代码片`111 //-127
short:短整型 在内存中占2字节
long:长整型 在内存中占4字节 (32位操作系统) (64位中占8字节)
long long:长长整型 在内存中占8字节
float:单精度浮点型(实型) 在内存中占4字节
用于展示小数,有效位数6~7位
double:双精度浮点型(实型) 在内存中占8字节 有效位数15~16位
3.9、变量
局部变量:
在函数内部(花括号{
}内部定义的变量)
作用域:模块(函数内部) (从定义开始位置,到函数结束)
生命周期:模块(函数)调用后结束
如果未初始化,系统随机赋值
全局变量:
在函数外部(花括号{
}外部定义的变量)
作用域:整个程序 (从定义开始位置,到程序结束)
生命周期:程序结束
系统默认初始化为0
正数:
原码:数据的二进制
反码:还是原码
补码:还是原码
负数:
原码:数据的二进制
反码:符号位不变,其他位取反
补码:反码+1(原码取反加1)
变量的存储形式(以补码的形式存储)
常量: 在程序运行中 始终不变的
(1)整型常量(十进制数、八进制数、十六进制数)
(2)实型常量a:小数形式 eg:3.14
b:指数形式 eg:12.34*10^3 ===> 12.34e3 e、E表示指数的底数10
注:e前面要有数字 e后面必须是整数
(3)字符常量:计算机内部按照ASCII码进行存储和处理
a:普通的字符:用单引号界定
eg:'a' 'A' '3' '#'
b:转义字符: 用\将字符 原本的含义 赋予新的含义
eg:'\n'
(4)符号常量:一般用在程序的开头,用预处理指令定义
#define 符号名 常量数据
eg:#define PI 3.14159
PI 就是符号常量 程序中,定义后的任意地方,都可用PI表示3.14159
注:符号名 符合命名规则 一般大写
变量:在程序中可以改变的数据(用户自定义)
必须先定义才使用
定义的一般形式:<存储类型><数据类型><变量名>
存储类型:(4G虚拟内存空间)
auto static register extern
auto:自动类型 栈区
auto int a;====> int a;
static:静态存储, 静态存储区(全局变量区)
只要程序一直运行,static修饰的变量就一直存在
register:寄存器类型,存放在寄存器的存储空间
效率高、可加快程序运行的速度
extern:外部引用(全局区)
赋值:
初始化:
int a = 10;
一般:int a;
a = 10;
3.10、输入输出
格式输出函数:(加头文件 #include <stdio.h>)
printf("字符"); //原样输出
printf("%格式控制符",指定的数据);//以固定的格式输出指定的数据
%d %c %s %f %p %%
%c //字符类型
%d //十进制整数
%x //十六进制无符号整数
%o //八进制无符号整数
%u //无符号十进制整数
%s //字符串
%e //指数形式浮点小数
%f //小数形式浮点小数
转义字符:用\将字符原本的意义改变 赋予新的含义
\n //换行
\t //水平制表符
\0 //空
\v //垂直制表符
\f //换页
\b //退格
\\ //代表一个反斜线字符‘\’
\' //代表一个单引号字符
\“ //代表一个双引号字符
\ddd //1到3位八进制数所代表的任意字符
\xhh //1到2位十六进制数所代表的任意字符
格式修饰符:
m %md //输出指定域宽,数字的长度>m,原样输出,小于m,左补空格
n %.nf //限制浮点数的小数位数(四舍五入)
# %#x //显示进制前的提示符0x 0
格式输入函数:
scanf("格式控制符",输入位置的地址);
格式控制符:%d %c %s %f
修饰符:m //指定域宽
l //双精度或长整型
h //短整型
* //抑制符
scanf 输入数据结束的标志:
空格 回车 tab
非法输入
m 指定域宽(123 m=2 12)
字符输入函数:getchar()
输入单个字符
变量名 = getchar();
清除垃圾字符
字符输出函数:putchar()
输出单个字符
putchar(变量名);
putchar(字符);//字符用‘’
putchar(ASCII);
字符串输入函数:gets()
gets(字符串的首地址);
以换行作为结束标志,空格能输入
//scanf把空格作为结束的标志之一
字符串输出函数:puts()
puts(字符串的首地址);
puts("字符串");
//后面会自动换行
使用scanf函数时,可能会产生垃圾字符,清除垃圾字符的方法:
getchar();
%*c //使用抑制符
3.11、转换、三目运算符
强制转换(不会四舍五入):
显示:(数据类型) 表达式
注:高->低 会丢失数据 一般不使用
eg:(double) a;//将a转换成double类型
(int)(x+y);//将x+y的值转换成int类型
隐式:自动进行的
低类型->高类型
有符号->无符号
char、short->int->unsigned->long->float->double
低 高
三目运算符:
a>b?a:b //判断a是否大于b,大于表达式的值为a,否则为b
逗号运算符:优先级最低 从左到右依次运算 表达式的值是最后一个
四、 判断、循环、跳转
4.1、if els
if 语句的基本形式
(1)单分支 (if语句)
if (表达式)
(2)双分支结构(if-else)
if(表达式) //表达式为真,执行语句块1
{
语句块1;
}
else //if表达式为假,执行语句块2
{
语句块2;
}
if(表达式) //表达式为真,执行语句块1
{
语句块1;
}
else if(表达式) //表达式为真,执行语句块2
{
语句块2;
}
else //if表达式为假,执行语句块
{
语句块;
}
注:else 必须和if搭配使用,它会自动向上寻找最近的if
else if必须和if搭配使用
练习1:在键盘上输入一个字符,判断是大写字母还是小写字母,是数字还是其他字符
2:猜硬币的小游戏
4.2、switch
switch(表达式)//表达式的结果一般为整型常量或字符常量
{
case 常量表达式1:语句块;break;
case 常量表达式2:语句块;break;
case 常量表达式3:语句块;break;
case 常量表达式4:语句块;break;
...
default:语句块;break;
}
练习:模拟简单的计算器,进行两个数的四则运算
4.3、while
while(表达式)//表达式为真,执行下面语句,为假时结束循环
{
语句块;
}
练习:求1+3+5+7.....的和,若累加数大于750时,程序终止并输出结果。
do//先执行一遍语句,再进行判断
{
语句块;
}
while(表达式)//表达式为真,执行上面的语句,为假时结束循环
练习:求1~1000之间,满足用3除余2,用5除余3,用7除余2的数
4.4、for
for(表达式1;表达式2;表达式3)
{
语句块;
}
(1)先执行表达式1,只执行一次
(2)执行表达式2,若其值非零(真),则执行for中指定的循环体中的语句;
执行第(3)步,若其值零(假),则结束循环,转到第(5)步,若其值零
(3)执行表达式3
(4)转回执行第(2)步,继续执行
(5)结束循环,执行for下面的语句
练习:1-3+5-7.....-99+101
for语句的其他形式
表达式的省略
(1)如果在for语句前给循环控制变量赋了初值,则表达式1可以省略,分号不能省略
i=1;
for(;i<=100;i++)
{
s=s+i;
}
(2)如果表达式3省略,则应在for语句的循环体内 修改循环控制变量
for(i=1;i<=100;)
{
s=s+i;
i++;
}
(3)如果表达式1和表达式3都省略,则for语句相当于while语句
i=1;//在for语句前给循环控制变量赋了初值
for(;i<=100;)
{
s=s+i;
i++;//在for循环语句内 修改循环控制变量
}
等价于
i=1;
while(i<=100)
{
s=s+i;
i++;
}
(4)如果三个表达式都省略,则可能死循环,在循环控制体中遇到break退出
1、break语句:switch语句中使用,跳过后面的语句
循环体内使用,跳出一层循环
2、continue语句:在循环语句内使用,跳出本次循环,进入下一次循环
3、return语句:结束整个函数
return 0;//默认规定, 0表示正常结束
return -1;//默认规定, -1表示异常结束
循环嵌套:
输出4*4整数矩阵
练习:打印*
**
***
****
*****
用循环控制变量i控制输出行
每行上*个数随行控制变量i变化
i=1,执行一次putchar('*');
外循环控制行:for(i=1; i<=5; i++)
内循环: for(j=1; j<=i; j++)
putchar(’*‘);//输出一行’*‘
练习1:求n的阶乘,n从键盘输入
练习2:循环从键盘输入字符,并统计其中数字字符的个数,用换行符结束循环
练习3:打印九九乘法表
练习4:利用*打印一个菱形
*
***
*****
*******
*********
*******
*****
***
*
4.5、goto
goto语句:直接跳转
使代码的可读性差,一般不使用,需要先定义标志
loop://名字自己定义
goto loop;
五、数组
5.1、一维数组
一维数组:
数组是一定有顺序关系的若干变量的集合 在空间中连续存储
(批量处理 数据类型相同的 一堆数据)
一般形式:
<存储类型><数据类型> 数组名[个数]
存储类型:auto static register extern
数据类型:char short int double float long
数组名:符合标识符的命名规则 一般由数字、字母、下划线组成,以字母或下划线开头
个数:元素个数 不能用变量定义
int a[10];//定义了10个整型元素的数组 数组名为a
char b[10];//定义了10个字符型元素的数组 数组名为b
初始化:<存储类型><数据类型> 数组名[个数] = {
元素值,元素值,元素值,元素值,....}
完全初始化:int a[5] = {
1,2,3,4,5};
部分初始化:int a[10] = {
1,2,3,4,5};
只给部分元素赋初值
当{
}中值的个数少于元素个数时,只给前面a[0]~a[4]赋初值,后面5个自动赋值为0
缺省初始化:int a[] = {
1,2,3,4,5};
使用:数组名 [下标]
a[9];//注,下标表示0~9 ,下标的上限为元素个数减1
遍历数组:
for(i=0; i<n; i++)
{
printf("%d\n",a[i]);
}
数组越界:
编译系统不会检查数组越界的错误,但可能回出现段错误
求数组元素个数:
sizeof(数组名)/sizeof(数据类型)
sizeof(a)/sizeof(int);//sizeof(a)/sizeof(a[0]);
数组清零:
(1)int a[10] = {
0};
(2)memset 或 bzero
头文件#include <string.h>
函数原型:void *memset(void *s, int c, size_t n);
void bzero(void *s, size_t n);
使用:memset(a, 0, sizeof(a));
bzero(a, sizeof(a));
练习5:定义了10个整型元素的数组,赋值0~9,逆序打印
练习6:定义了10个整型元素的数组,随机输入各元素的值,并找出其中的最大值
练习7:将1~1000中所有的11的倍数存在数组中,打印输出
冒泡排序:
for(i=0; i<9; i++)//外层循环实现排序数据9趟比较
for(j=0; j<9-i; j++)//内循环语句采用逐个比较 交换的方式将最大数交换至数据末尾
{
if(a[j] > a[j+1])
{
a[j] = a[j]^a[j+1];
a[j+1] = a[j]^a[j+1];
a[j] = a[j]^a[j+1];
}
}
数据交换:
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
5.2、二维数组
二维数组:
一般形式:
<存储类型><数据类型> 数组名[个数][个数]
//<存储类型><数据类型> 数组名[行][列]
存储类型:auto static register extern
数据类型:char short int double float long
数组名:符合标识符的命名规则 一般由数字、字母、下划线组成,以字母或下划线开头
个数:元素个数 不能用变量定义
int a[3][4];
初始化:
<存储类型><数据类型> 数组名[个数][个数] = {
元素值,元素值,元素值,元素值,....}
int a[3][3] = {
1,2,3,4,5,6,7,8,9};
(1)若对全部元素赋初值,则一维的长度可以省略
int a[][3] = {
1,2,3,4,5,6,7,8,9};
//int a[3][] = {1,2,3,4,5,6,7,8,9}; 不能省略二维的长度
(2)对部分元素赋初值,未赋初值的部分自动取0
int a[3][3] = {
{
1},{
2},{
3}};//对每一行的第一列元素赋初值
1 0 0
2 0 0
3 0 0
int a[3][4];
//二维数组可以分解为多个一维数组
//一维数组名:a[0]、a[1]、a[2]
//三个一维数组 每个数组中都包含4个元素
按行赋值:
int a[3][3] = {
{
1,2,3},{
5,4,7},{
6,8,9}};
练习1:求4名同学的3门学科,单科成绩的平均分,所有科目总的平均分
练习2:从键盘上读入3行4列12整数构成的矩阵,转入二维数组a中,将转置后的结果放在数组b中,输出结果
1 2 3 4 1 5 9
5 6 7 8 ====》 2 6 10
9 10 11 12 3 7 11
4 8 12
5.3、一维字符数组
一维字符数组:
char a[5] = {
'h','e','l','l','o'};
char a[] = {
"hello"};
注:字符数组,不等于字符串
字符串:“hello”
可以当成字符串一次性输入、输出 gets、puts
字符数组:char a[]={
"hello"};//注意不要越界,字符串后'\0'
练习3:单词的逆序 hello world逆序===》dlrow olleh
练习2:从键盘输入字符串,求字符串中空格数
5.4、二维字符数组
二维字符数组:
char a[][10] = {
“good","better","wonderful"};//注意字符和字符串区别
求行数:int n = sizeof(a)/sizeof(a[0]);
求一行元素个数:int column_num = sizeof(a[0])/sizeof(char);
字符串相关函数
(1)字符串输入函数 gets()
格式:gets(字符数组名)
功能:从标准输入设备键盘输入一个字符串,并存到指定的字符数组中
本函数正常执行后得到一个函数返回值,即字符数组的首地址
头文件#include <stdio.h>
char ch[15];
gets(ch);//输入字符串中含有空格时,输出仍为全部字符串,以回车作为输入结束
puts(ch);
(2)字符串输出函数 puts()
格式:puts(字符数组名)
功能:将字符数组中的字符串输出到显示器
(3)求字符串长度函数 strlen()
头文件#include <string.h>
函数原型:size_t strlen(const char *s);
//计算字符串有效长度 不包括'\0'
用法:int len = strlen(字符数组名);
(4)字符串连接函数 strcat()
头文件#include <string.h>
函数原型:char *strcat(char *dest, const char *src);
用法:strcat(字符数组名1,字符数组名2);
功能:把字符数组2中的字符串连接到字符数组1后,并删除字符数组1结束标志'\0'
函数返回值:字符数组1首地址
注:字符数组1应定义足够长度
(5)字符串拷贝函数 strcpy()
头文件:#include <string.h>
函数原型:char *strcpy(char *dest, const char *src);
用法:strcpy(字符数组名1,字符数组名2)
功能:将字符数组2中的字符串拷贝到字符数组1中,字符串2结束的标志'\0'也一同拷贝
注:字符数组1应定义足够长度
(6)字符串比较函数 strcmp
头文件:#include <string.h>
函数原型:int strcmp(const char *s1, const char *s2);
用法:strcmp(字符数组名1,字符数组名2);
功能:按照 两个数组中字符串的排列顺序 逐次比较 对应字符的ASCII码值,返回比较结果
a:字符串1 = 字符串2 ,返回0
b:字符串1 > 字符串2 ,返回1
c:字符串1 < 字符串2 ,返回-1
练习:输入5个国家英文名称,按字母顺序排序输出
China italy Germany French Spain
六、指针
6.1、指针
地址:内存中 以字节为单位 开始编号
变量在内存单元上的编号,地址是常量
1Byte = 8 bit
指针:本质 内存单元的地址
指针变量: 专门用来存放地址的变量
指针的字节大小不会因为数据类型的改变而改变,都是4字节,与操作系统有关
一般形式:<存储类型><数据类型> *<变量名>
int *p;//*表示p是一个指针变量,前面的int类型 表示p可以指向一个整型数据
(1)指针的存储类型指 指针变量本身的存储类型
(2)指针的数据类型指 指针目标 的数据类型
初始化:<存储类型><数据类型> *<变量名> = <地址量>
int a = 10;
int *p = &a;
赋值:
int a = 10;
int *p;
p = &a;
使用:
&:取变量的地址
*:取地址中的内容 //单独使用
两个互为逆运算 *p == *(&a) == a
野指针:只是定义了指针,没有目标地址,会非法访问内存(段错误)
练习1:利用指针 输入两个整数 按先大后小的顺序输出
指针变量的运算:
本质:地址的运算
(1)算术运算:(+ - ++ --)
int *p;
p+n;//p+n*sizeof(p的数据类型)---->向高地址偏移了n个数据
p++;//p=p+1
++p;
p-n;//p-n*sizeof(p的数据类型)---->向低地址偏移了n个数据
p--;//p=p-1
--p;
q-p;//前提是p、q数据类型一致,结果是两个指针之间的元素个数
//(q-p)/sizeof(数据类型)
注:p+n只是单纯的运算,p的指向不变
p++指向改变,指向了下一个数据,p的内容发生了改变
(2)关系运算(>= <= < > == !=)
前提:指针的类型相同
p > q:比较的是指针变量存放地址的高低
void *指针:是一种不确定的数据类型的指针,它可以指向任意的数据类型
但是在使用时需强制类型转换
为了防止野指针,int *p = NULL;
//int *p;
//p = NULL;//赋值 p指向NULL
if(q == NULL)
{
print(”q = NULL“);
return -1;
}
6.2、二级指针
二级指针:
指向指针的指针
多级指针:
指针的迭代
const 指针
const 被修饰的部分只读,限制更改
int a = 10;
int b = 90;
(1)const int *p = &a;//限制*p,p指向的内容不能改变
int const *p = &a;//一样
//*p = 88;error
(2) int * const p = &a;//限制p,p的指向不能改变
//p=&b ;//error
(3)const int * const p = &a;//同时限制*p和p,p指向的内容和p的指向都不能改变
int const* const p = &a;//同时限制*p和p,p指向的内容和p的指向都不能改变
//*p = 88;error
//p=&b ;//error
6.3、指针与一维数组
指针和一维数组:
数组名可代表数组的首地址,数组在内存中是连续的
数组名的意义:int a[10];
1:a 代表 数组 首元素的首地址(地址是常量)
2:a 代表 整个数组 eg:sizeof(a)求整个数组的大小
int a[10] = {
1,2,3,4,5,6,7,8,9,10}
int *p;
p = &a[0];//p=a;
a[0] <==> *p <==> *a <==> p[0]
a[5] <==> *(p+5) <==> *(a+5) <==> p[5]
a[i] <==> *(p+i) <==> *(a+i) <==> p[i]
指针和数组名都可以表示地址
注意区别:指针是变量 数组名是常量
练习2:用两个指针将数组元素打印成 6,7,8,9,10,1,2,3,4,5,
int a[10] = {
1,2,3,4,5,6,7,8,9,10}
int a[10] = {
6,7,8,9,10,1,2,3,4,5}
指针和字符数组:
char ch[5] = {
'h','e','l','l','o'};
char ch[6] = "hello" //本质是数组,改变的是数组中的内容
char *p = "hello";
char *q = "hello";
//*p = 'w';段错误
字符串常量,将字符串的首地址直接给指针p,内容不能更改
练习1:用指针的方式完成strcat()函数功能
练习2:用指针的方式完成strcpy()函数功能
6.4、指针与二维数组
指针和二维数组:
[]:单独使用,有降级的作用
二维数组名:代表一行的首地址
二维数组名+1 偏移一行
数组指针:
本质是指针,指向一维数组的首地址
int a[3][2] = {
{
1,2},{
3,5},{
4,89}};
int (*p)[2];//数组指针 p的类型 int (*)[2] 指向整数 步长以两个整数为单位
列数:一维数组最多能存放的元素个数
特点:指向一片连续的空间,方便操作
a[m][n] <==> *(a[m]+n) <==>(*(a+m))[n] <==> *(*(a+m)+n)
p[m][n] <==> *(p[m]+n) <==>(*(p+m))[n] <==> *(*(p+m)+n)
二维数组中:
a[i][j]<==>p[i][j]<==>*(*(p+i)+j)<==>*(*(a+i)+j)
指针数组:
本质是数组(一维数组),数组中存放的是指针
int *p[3];
p//数组指针名 不能自加
p[0]//指针数组中的第一个元素,是一个指针,能自加
*p[1]//对数组中的第二个元素取内容
char a[3][15] = {
"you","are","a good person"};
char *p[3] = {
"to","be","a better man"};
printf("%s\n",a[0]);//you
printf("%s\n",a[1]+1);//re
printf("%c\n",*(a[2]+5));//d
printf("%c\n",*(*(a+2)+5));//d
printf("%s\n",p[2]);//a better man
printf("%s\n",p[2]+9);//man
printf("%c\n",*(p[2]+10));//a
练习3:通过指针实现,输入字符串,删除指定的字符//eg:abbcdef 删除b acdef
练习4:通过指针实现,输入字符串,删除指定的字符串//eg:abbccdef 删除bc adef
练习1:有5个字符串,首先将它们按照字符串中的字符个数由小到大排列,再分别取出每个字符串的第三个字母合并成一个新的字符串输出(若少于三个字符的输出空格)。要求:利用字符串指针和指针数组实现。
六、函数
6.1、函数
函数:
函数:完成特定功能的代码块,可重复调用----建立公用模块、消除重复工作、提高程序开发效率
一般形式(定义):
<数据类型><函数名>(<形式参数说明>)
{
代码块;//实现功能
return<表达式>;//表达式的类型与函数数据类型一致
}
数据类型:指的是函数返回的数据类型,可以为空(void),省略时默认int类型
函数名:符合标识符的命名规则,最好见明知意
形式参数说明:想要传入函数的数据类型
<数据类型><函数名>(<形参1>,<形参2>,<形参3>,<形参4>.....)
int fun(int a,int b,int c)
{
int sum = a+b+c;
return sum;
}
函数调用:
<函数名>(<实际参数>)
<函数名>(<实参1>,<实参2>,<实参3>,<实参4>.....)//实参个数与形参个数一致
fun(1,2,3);//int a = 1,int b = 2,int c = 3;
//fun(1,2);//error 实参个数与形参个数一致
函数声明:
提前打招呼,声明这个程序中有这个函数,具体的功能实现代码在后面
1.当功能函数放在主函数(main)前面,声明、定义在一起
2.当功能函数放在主函数(main)后面时使用,声明语句放在头文件下面,主函数上面
int fun(int a,int b,int c);
int fun(int ,int ,int );
//声明时可以省略形参的名字,保留数据类型
1.函数类型
和返回值紧密联系
返回值的数据类型 和 函数的数据类型 必须一致!
由函数功能 决定 返回值 的类型有无
主函数内的返回值:(程序员默认规定)
return 0;//程序正常结束
return -1;//程序非正常结束
没有返回值
void func()
{
//1.直接不写返回值
return;//2.只有return
}
返回值的使用:
1:定义变量来接收 //int ret = sum(1,2,3);
2:直接使用 //printf("%d\n",sum(1,2,3));
2:函数的参数
实际参数(实参):
具体传进函数内部的参数(变量的值)
类型和形参一致
个数和形参一致
形式参数(形参)
定义时:需要传进函数的参数的 形式说明
被调用时:程序会定义形参为局部变量,将实参的值赋值给形参变量
3:函数的功能实现代码
具体的代码,实现函数的功能
//main 函数为人机交互的接口
4:写一个函数
(1)思考函数的功能--函数名
(2)思考参数
(3)思考返回值(数据类型)
(4)实现的代码
函数的传参:
1、赋值传递(复制传递、值传递)
将实参的值拷贝给形参,实参和形参时两个空间的变量
改变形参的值不会改变实参
2、地址传递(指针传递)
将实参的地址 给 形参(形参指针)
形参通过地址来操作实参变量
3、全局变量(不需要传参)
全局变量整个程序都能使用
练习1:将10进制转成2进制
6.2、数组的传参
char ch[64] = {
0};
(1)定义指针
void func(char *s)// func(ch) ch *s = ch;
eg:
int a[10] = {
0};
fun(a); //int *p = a;
void fun(int *p) //int *p = a;
{
}
int a[3][10] = {
0};
fun(a); //int (*p)[] = a;
void fun(int (*p)[])//int (*p)[] = a;
{
}
(2)定义成数组 (不建议使用)
void func(char s[]);//在函数的形参中,s表示的指针,而不是数组
eg:
int a[10] = {
0};
fun(a); //int p[10] = a;
void fun(int p[10]) //int p[10] = a;
{
}
int a[3][10] = {
0};
fun(a); //int p[][] = a;
void fun(int p[][10])//行可以省略
{
}
两种方式形式不同,但意义都是指针
练习2:求2的4次方
练习3:删除字符串中重复的字符
大小端存储:
大端存储:低数据位存放到高地址中,高数据位存放到低地址中
小端存储:低数据位存放到低地址中,高数据位存放到高地址中
练习1:删除一个字符串中所有的空格
6.3、指针函数
指针函数:
int *func();
本质是函数,特殊之处在于返回值为指针(地址)
注意:返回的地址是否有效(是否能使用),不能返回局部变量的地址
能返回的地址:
1、全局变量的地址
2、static修饰的地址
3、返回能传入参数的地址(主函数中的地址,传入被调函数中)
4、字符串常量的地址
5、malloc申请空间
练习2:输入三个整数,按先大后小的顺序输出
练习3:用函数调用实现字符串的复制
6.4、函数指针
int (*func)();
本质是指针,用来存放函数的地址,指向函数的入口地址(函数名)
<数据类型>(*<函数指针名>)(<形参>);
int (*p)(int a,int b);
<数据类型>:函数指针 所指向的 函数的返回值的 数据类型
<函数指针名>:符合标识符的命名规则,最好见明知意
<形参>:与函数指针 所指向的函数的形参 一致(相当于声明),形参名可以省略
目的:指针可以指向很多同类型的函数(参数 返回值一致),调用的地方不变,使函数更加通用
优点:可用一个指针调用多个同类型函数
练习4:实现两个整数的加、减、乘、除运算
用户通过输入1、2、3、4分别进行两个整数的加、减、乘、除运算,并输出结果
练习5:约瑟夫环 有n个人围成一圈。从第一个人开始开始报数(从1到3报数),
凡是报到3的人退出圈子,最后留下来的让你使原来的第几号
函数指针数组:
int (*arr[4])(int,int);
//数组里 指针指向 参数为两个int类型的函数地址
练习7:将n个数输入时顺序的逆序排列,用函数实现
6.5、递归函数
一个函数的函数体中直接或间接调用了该函数本身
函数调自己。注意设置边界条件(终止条件)
分为两个阶段:递推、回归
三要求:
1、递归终止条件,即递归函数的出口
2、不断的递归调用本身
3、递归函数的主体内容,即递归函数需要做的事情
练习8:求n!
练习9:斐波那契数列 F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2) (n≥2,n∈N*)
0 1 1 2 3 5 8 13 21 34.......
extern:外部变量的声明(函数外部,文件外部)
对 一个在其他地方定义的变量,进行一次重复引用,(不会产生新的变量)
扩大了作用域
static:静态数据
1、修饰局部变量,延长生命周期
2、修饰全局变量,限制作用域 (和extern互斥,不能在其他文件中使用)
3、修饰函数,限制作用域
const:
1、修饰指针,根据位置不同,限制的内容不同
const int *p;
int * const p;
const int *const p;
2、修饰变量,将变量常量化,不能在后面被改变(需要初始化)
3、修饰形参,表明只是输入参数,不能在函数内部改变
typedef:取别名
为现有类型取别名
七、结构体
结构体的定义说明了它的组成成员,以及每个成员的数据类型
定义形式一般如下:
struct 结构类型名
{
数据类型 成员名1;
数据类型 成员名2;
数据类型 成员名3;
......
数据类型 成员名n;
};//分号不能少!
结构体的初始化的一般形式如下:
strcut 结构类型名 结构变量 = {
初始化数据1,.....初始化数据n};
结构体变量说明的一般形式:
strcut 结构类型名 结构变量;
在程序中使用结构体中成员的方法:
结构变量名.成员名称
C语言源码下载地址:https://download.csdn.net/download/qq_43498137/22171766