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)十进制
        基数:100 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
     基数:80 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
	基数:160 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、关键字

按作用分类:关键字、标识符、分隔符、运算符、标点符号
关键字:32auto:声明自动变量  一般不使用
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、数据类型

基本数据类型:charshortintlongfloatdouble
存储类型(有符号、无符号)signedunsignedstaticregisterexternconstvolatileauto
语句:ifelseforwhiledogotoswitchcasedefaultbreakcontinuereturn
构造:unionstructenum、
求字节: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 

    位运算的一般用法:对指定位清01
	           //位运算的位置从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~7double:双精度浮点型(实型)  在内存中占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类型
	
    隐式:自动进行的
        低类型->高类型
        有符号->无符号
    charshort->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:语句块;breakcase 常量表达式2:语句块;breakcase 常量表达式3:语句块;breakcase 常量表达式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退出

1break语句:switch语句中使用,跳过后面的语句
            循环体内使用,跳出一层循环

2continue语句:在循环语句内使用,跳出本次循环,进入下一次循环

3return语句:结束整个函数
           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:从键盘上读入3412整数构成的矩阵,转入二维数组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:求24次方
练习3:删除字符串中重复的字符

大小端存储:
大端存储:低数据位存放到高地址中,高数据位存放到低地址中
小端存储:低数据位存放到低地址中,高数据位存放到高地址中

练习1:删除一个字符串中所有的空格

6.3、指针函数

指针函数:
int *func();
本质是函数,特殊之处在于返回值为指针(地址)
注意:返回的地址是否有效(是否能使用),不能返回局部变量的地址
     能返回的地址:
	 1、全局变量的地址
	 2static修饰的地址
	 3、返回能传入参数的地址(主函数中的地址,传入被调函数中)
	 4、字符串常量的地址
	 5、malloc申请空间

练习2:输入三个整数,按先大后小的顺序输出
练习3:用函数调用实现字符串的复制

6.4、函数指针

int (*func)();
    本质是指针,用来存放函数的地址,指向函数的入口地址(函数名)
	<数据类型>(*<函数指针名>)(<形参>)int (*p)(int a,int b);
	<数据类型>:函数指针 所指向的 函数的返回值的 数据类型
	<函数指针名>:符合标识符的命名规则,最好见明知意
	<形参>:与函数指针 所指向的函数的形参 一致(相当于声明),形参名可以省略
	
	
	目的:指针可以指向很多同类型的函数(参数 返回值一致),调用的地方不变,使函数更加通用
	优点:可用一个指针调用多个同类型函数


练习4:实现两个整数的加、减、乘、除运算
      用户通过输入1234分别进行两个整数的加、减、乘、除运算,并输出结果

练习5:约瑟夫环  有n个人围成一圈。从第一个人开始开始报数(13报数),
   凡是报到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

跳转:下一篇、Linux c高级

跳转:下一篇、Linux c高级

跳转:开头

猜你喜欢

转载自blog.csdn.net/qq_43498137/article/details/120126613
今日推荐