Linux C语言

摘抄自网络!

-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

词法符号:程序设计语言中有若干字符组成的有意义的 最小语法单位
123456789101112131415161718192021


## 3.3、关键字

```c
按作用分类:关键字、标识符、分隔符、运算符、标点符号
关键字: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:声明静态变量
12345678910111213141516171819202122232425262728293031323334

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
1234567

3.5、标识符

     程序员按照命名规则自行定义的词法符号
	
	命名规则:
	1、由字母、数字、下划线(_)组成
	2、不能和关键字重名
	3、只能由字母或下划线开头
	
	标识符的命名方式:
	见名知意
	
	骆驼命名法:混合大小写字母构成变量名或函数名
	小驼峰:
	    常用于变量
		eg:myFirstName 
    大驼峰(帕斯卡命名法):
	    常用于类名、函数名
		eg:DataBaseUser
    下划线命名法:
	    eg:print_students_count();
 
 linux下严格区分大小写!
123456789101112131415161718192021

3.6、分格符

空格 ‘ ’    32
	换行 ‘\n’   10
	制表符 '\t' 9

    注释:1、/*提示信息,注释一段内容*/
	      2、//注释一行内容
		  3、#if 0 
		       中间内容被注释
			 #else
				中间内容正常执行
			 #endif

			#if 1
		       中间内容正常执行
			 #else
				中间内容被注释
			 #endif
1234567891011121314151617

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()
	
	标点符号:
	, ; () {}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051

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位
1234567891011121314151617181920212223242526272829303132333435

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;	
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061

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  //使用抑制符
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071

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

逗号运算符:优先级最低 从左到右依次运算 表达式的值是最后一个	
12345678910111213141516

四、 判断、循环、跳转

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:猜硬币的小游戏
12345678910111213141516171819202122232425262728293031323334

4.2、switch

 switch(表达式)//表达式的结果一般为整型常量或字符常量
 {
	 case 常量表达式1:语句块;break;
	 case 常量表达式2:语句块;break;
	 case 常量表达式3:语句块;break;
	 case 常量表达式4:语句块;break;
	 ...
	 default:语句块;break;
 } 
 
练习:模拟简单的计算器,进行两个数的四则运算 
1234567891011

4.3、while

while(表达式)//表达式为真,执行下面语句,为假时结束循环
{
	语句块;
}
练习:求1+3+5+7.....的和,若累加数大于750时,程序终止并输出结果。	

do//先执行一遍语句,再进行判断
{
	语句块;
}
while(表达式)//表达式为真,执行上面的语句,为假时结束循环
练习:求1~1000之间,满足用3除余2,用5除余3,用7除余2的数
123456789101112

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:利用*打印一个菱形
        *
       ***
      *****
     *******
    *********
     *******		
      *****		
       ***		
        *
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384

4.5、goto

goto语句:直接跳转
        使代码的可读性差,一般不使用,需要先定义标志
		loop://名字自己定义
		goto loop;
1234

五、数组

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;

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172

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
123456789101112131415161718192021222324252627282930313233343536373839

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:从键盘输入字符串,求字符串中空格数
123456789101112

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
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

六、指针

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;
			   }

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667

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
1234567891011121314151617181920212223

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()函数功能		
1234567891011121314151617181920212223242526272829303132333435363738

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个字符串,首先将它们按照字符串中的字符个数由小到大排列,再分别取出每个字符串的第三个字母合并成一个新的字符串输出(若少于三个字符的输出空格)。要求:利用字符串指针和指针数组实现。	

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748

六、函数

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进制
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788

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:删除字符串中重复的字符

123456789101112131415161718192021222324252627282930313233343536373839404142

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

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

6.3、指针函数

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

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

1234567891011121314

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个数输入时顺序的逆序排列,用函数实现
123456789101112131415161718192021222324

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:取别名
    为现有类型取别名
1234567891011121314151617181920212223242526272829303132

七、结构体

结构体的定义说明了它的组成成员,以及每个成员的数据类型
   定义形式一般如下:
   
   struct 结构类型名
   {
	   数据类型 成员名1;
	   数据类型 成员名2;
	   数据类型 成员名3;
	   ......
	   数据类型 成员名n;
   };//分号不能少!

   结构体的初始化的一般形式如下:
   strcut 结构类型名 结构变量 = {初始化数据1,.....初始化数据n};
   
   结构体变量说明的一般形式:
   strcut 结构类型名 结构变量;
   
   在程序中使用结构体中成员的方法:
   结构变量名.成员名称
1234567891011121314151617181920

在这里插入图片描述
在这里插入图片描述

C语言源码下载地址:https://download.csdn.net/download/qq_43498137/22171766

跳转:下一篇、Linux c高级

跳转:下一篇、Linux c高级

跳转:开头