C语言学习总结

### C语言的开发工具

**Visual Studio 2022**

https://visualstudio.microsoft.com/zh-hans/downloads/



### C语言的开源库非常丰富

C语言的开源库非常丰富,以下是一些常见且受欢迎的库:

C标准库:这是C语言自带的标准库,提供了基础的输入输出操作、内存管理、字符处理等功能。



C标准库扩展:例如 GNU libc,提供了标准库中未包含的额外功能。



数据结构和算法库:

GLib供了很多常用的数据结构和算法,广泛用于GNOME等项目。

linq语言的LINQ实现。



多媒体处理库:

FFmpeg:用于处理音频和视频的开源项目。

libswresample:FFmpeg的一部分,提供音频和视频的重采样。



图形和游戏开发库:

SDLimple DirectMedia Layer,用于跨平台的游戏开发。

Allegro:一个成熟的游戏程序库,提供丰富的图形和媒体支持。



网络库:

cURL于传输数据的客户端库,支持多种协议。

libssh:用于SSH连接和操作的库。



文本处理库:

PCREerl Compatible Regular Expressions,用于正则表达式的处理。

Oniguruma:另一个正则表达式引擎,支持多语言。



并发和多线程库:

POCOPortable Component-based Server and Application Framework for C++。

libuv:跨平台的事件循环,常用于Node.js的C语言后端。



安全和加密库:

OpenSSL:用于加密通信的库,广泛应用于安全系统。

TLS:用于数据加密传输的安全协议。



物联网库:

mbedTLS:提供安全的传输层加密,适用于内存和处理能力有限的设备。

LiteOS:华为开源的物联网操作系统。



机器学习库:

darknet:一个用于计算机视觉的开源的、简单的、快速的的神经网络框架。

TensorFlow Lite:TensorFlow的轻量级版本,适用于移动和嵌入式设备。



单元测试库:

CUnit:用于C语言的单元测试框架。

CMock:用于C单元测试的模拟框架。

**

#include 
空行
main函数 主函数
函数体
执行语句 prntf();
return 
/**/ //

//==========================================





### 1 数据类型

比方:室内类型,室外类型

1,基本类型
2,构造类型
3,指针类型
4,空类型



基本类型:
	整型(基本整型,短整型,长整型)
 	字符型
 	浮点型(单精度,双精度)

构造类型(数组,结构体,共用体)
指针类型 ( *p ) 
空类型 ( void ) 





### 2 常量

1,数值型常量(整型常量,实型常量)
2,字符型常量
3,符号常量

数值型常量
   	整型常量(八进制 0前缀 0-7 ,十进制  0-9 ,十六进制 0x前缀 0-9 A-F a-f)
   	浮点型常量 - 实型常量(单精度,双精度)
   	字符型常量 (字符常量,字符串常量)

符号常量
	#define 
	const





### 3 转义字符

\n 回车换行
\t  
\v 
\b 退格
\r  回车
\f 





### 4 变量

1,整型变量
2,实型变量
3,字符型变量



整型变量
	有符号基本整型  int name
	无符号基本整型  unsigned name
	有符号短整型     short name
	无符号短整型     unsigned short name
	有符号长整型     long name
	无符号长整型     unsigned long name
	
实型变量
	单精度 float    -3.4*10^38 - 3.4*10^38
	双精度 double -1.7*10^-308 - 1.7*10^308 
	长双精度  -1.2*10^-4932 - 1.2*10^4932

字符型变量
char name;





### 5 混合运算







### 6 运算符与表达式

赋值运算与赋值表达

```c
类型 变量名 = 常数;
int  name = val;
```

类型转换
	自动类型转换 
		float i = 10.1f
		int j = i;

```c
强制类型转换
	float i = 10.1f
	int j = (int) i;
```

算术运算符与算术表达式
	

```c
算术的一些表达式

int ++i;
int i++;
int  --i;

&& 和
||     或
!    非

复合运算:
int value;
value+=3;
```

注释:

	/*注释内容*/
	//注释内容



sizeOf 运算符:

```c
//取得数据类型内存的空间大小
char name;
sizeOf(name); 
```





### 7  数据输入输出

putchar(); 字符输出
getchar(); 字符输入
puts(); 字符串输出
gets(); 字符串输入
printf(); 格式化输出
scanf(); 格式化输入


​	
字符输出 putchar();

```c
	#include<stdio.h>

	int main(){
		//printf("第一个c\n");
		putchar(int name);  //字符输出
		return 0;

	}
```


字符输入 getchar();
		#include<stdio.h>

```c
	int main(){
		//printf("第一个c\n");
		int i = getchar("请输入单个字符");  //字符输入
		return 0;

	}
```

字符串输出 puts();

```c
puts();
```

字符串输入 gets();

	gets();

格式化输出 printf();
	

	printf();

格式化输入 scanf();

	scanf();


==================================================

格式控制符:
%d:用于输出十进制有符号整数。
%u:用于输出十进制无符号整数。
%f: 用于输出十进制浮点数字。
%e   或 %E:用于输出指数形式的浮点数。
%g   或 %G:用于输出浮点数,根据数值大小自动选择使用 %f 或 %e。
%o   用于输出无符号八进制。
%x   或 %X:用于输出无符号十六进制。
%c   用于输出单个字符。
%s   用于输出字符串。
%p   用于输出指针地址。
%lu  用于输出无符号长整型。
%lld 或 %I64d:用于输出有符号长长整型。
%llu 或 %I64u:用于输出无符号长长整型。
%Lf  用于输出长双精度浮点数。
%%  格式控制符:用来输出百分号 %,在输出时需要使用两个百分号连在一起。

格式修饰符:
-:左对齐。
+:输出符号(正数前面加上“+”)。
#:八进制前缀(0)、十六进制前缀(0x 或 0X)或浮点数小数点(.)。
0:用 0 在左侧填充数据输出的空白,而不是默认的空格字符。
m.n:m 是指定的最小宽度,n 是指定的精度。
*:用来接收动态传入的宽度和精度。例如,%*.*f 表示输出浮点数,宽度和精度由后面带两个 int 类型的参数动态传入。
转义字符:
\a:警报(响铃)。
\b:退格(回退)一格。
\f:换页。
\n:换行。
\r:回车。
\t:水平制表符。
\v:垂直制表符。
\\:反斜杠。
\':单引号。
\":双引号。
\?:问号。
\0:字符串结束标志。

==================================================



### 8  循环控制 

//=== 选择结构

```c
if(){}

if(){}else{}

if(){}else if(){}

if() 嵌套
```


//=== 条件运算符

条件运算符,PHP的三元运算符
	表达式1 ? 结果a : 结果b; 

```c
switch(){}语句
	switch(){
		case 1:
			printf();
			break;
		case 2:
			printf();
			break:
		case 3:
			printf();
			break;
		default : 
			printf();
			break;
	}
```




//=== 循环控制

```c
cwhile语句
	while( n< 10){
		printf();	
	}

do... while语句
	do{
		int name++;
	}while(name<10);

for语句
	for(i=1; i<10; i++){
		printf
	}
```

//=== 转移语句

```c
goto语句
	goto name;
	

	name:
		//代码块.........

break语句

continue语句
	continue;

​	 
```



### 9 数组

一维数组
二维数组
多维数组
字符数组(字符数组,可以存放字符串)
多维数组


一维数组
	int arr[5];
	

```c
int arr[6] = { 1,2,3,4,5 }

int arr[6] = { 1,2,3 }     arr[0] = 1  arr[1] = 2  arr[2] = 3

int arr[] = { 1,2,3 }
```

二维数组
	

```c
inf arr[3][4];
		arr[0][0] arr[0][1] arr[0][2] arr[0][3] 
		arr[1][0] arr[1][1] arr[1][2] arr[1][3]  
		arr[2][0] arr[2][1] arr[2][2] arr[2][3]  
		

		00 01 02 03
		10 11 12 13
		20 21 22 23
	
		0 1 2 3
		1
		2


#include<stdio.h>

int main(){
	int ar[3][3];
	int i,j;

	for(i=0; i<3; i++){
		for(j=0; j<3; j++){
			printf("ar[%d][%d]",i,j);
			scanf("%d",&ar[i][j]);
		}
	}


	printf("输出二维数组\n");



	
	for(i=0; i<3; i++){
		for(j=0; j<3; j++){
			printf("%d\t",ar[i][j]);
		}
		printf("\n");
	}
	return 0;
}
```





字符数组




注: c语言中,没有字符串变量,没有String类,以字符数组的形式存放字符串。
	字符数组保存字符串时,会末尾多加一个  \0
例:
char ar[] = "abcdef";

内存中的情况如下:
a b c d e f \0



//字符数组的输入和输出
可以使用 %c   %s    前者逐个,后者整个字符串输出。

```c
for(i=0; i<5; i++){
	printf("%c\n",ar[i])l;
}


int ar[] = "abcdef";
prntf("%s\n",ar)j;


//定义数组1
char ar[5];

ar[0]="a";
ar[1]="b";
ar[2]="c";
ar[3]="d";
ar[4]="e";

//定义数组2
char ar[5] = {'a','b','c','d','e',}

//定义数组3
char ar[] = {'a','b','c','d','e',}


//定义数组4   注意:这个方法用的最多!!!!
char ar[] = "abcdef";
```

====================================

demo:

```c
#include<stdio.h>

int main(){
	char str[5]={'a','b','c','d'};
	int i;

	for(i=0; i<10; i++){
		printf("%c",str[i]);
	}
	return 0;

}


	char str[5]={'a','b','c','d'}; //字符数组
	
	char str[] = "abcd"  //存放字符串
	
	%c  逐个输出
	
	%s  整个字符串输出  


```

多维数组


数组的排序算法

嵌套循环原理: 外边循环一次,里边全部循环完。

	选择排序
	冒泡排序
	交换排序
	插入排序
	拆半排序



========================================================	





### 10 函数

```c
#include<stdio.h>

void smfun(int a, int b);  //函数声明
int main(){
	//语块
}
void smfun(){
	//语块
}


```

//=函数参数:  形参,实参。

```c
#include<stdio.h>

void smfun(int a, int b);  //函数声明    a b 函数的形参
int main(){
	//语块
	smfun(int 1, int 2); //实参  调用函数时的参数
}
void smfun(){
	//语块
}
```


//==数组做为函数的参数:

```c
#include<stdio.h>
void getva(int a);

int main(){
   //声明参数
   int i,j;
   int ar[5];
    
   //建数组 for
   for(i=0; i<5; i++){
        ar[i];
   }

   //循环输出数组参数的函数 for
   for(j=0; j<5; j++){
        getva(ar[i]);
   }
    return 0;
}
```

//函数

```c
void getva(int a){
   printf("这是一个数组函数参数的%d\n",a);
}
```


//==数组名做为函数的参数:
数组名表示数组中第一个元素的地址;


//==长度可变数组作为函数参数:
未指明数组大小,就属于长度可变的数组作为函数参数;


//==函数的调用和返回

语句调用        int  fun();
表达式调用     iRes = iNum3*Addnum(3,4);
函数参数调用  fun(10,funadd(3,5));

//=返回值

return 0;

//==函数的嵌套调用

不允许嵌套定义,可嵌套调用

//==函数的递归调用

函数调用自已。

涉及指针,回头再学

//==内部函数和外部函数

内部函数,static int add() 也叫静态函数,不可以源文件外调用
外部函数,extern int add() , 可以被其它源文件 调用;

//==局部变量和全局变量

局部使用的变量
全局变量,外部访问使用 extern 进行修饰;

//==常用标准函数库

编译系统会提供一些标准函数库;

数学函数库
字符判别函数库
字符串处理函数

========================================================	

//=函数
void fun(){
}

int main(){
	//.....
	return;
}



//函数定义
void fun(int a){
	//函数体
}



//函数形参和实参
void fun(形参){
}

void  fun(实参){
}



//数组做函数的参数   注:和正常的变量一样。
void fun(){}
int main(){
	int ar[10] = "0,1,2,3,4,5,6,7,8,9"
	for(i=0;i<10;i++){
		fun(ar[i]);
	}
}




//数组名作为函数的参数     注:和正常的变量一样。

数组名,为数组的第一个元素地址;


//长度可变数组作为函数的参数

2个字符串连接

```c
#include<stdio.h>

void str(char str1[],cha str2[]){
	int i,j;
	for(i=0; str1[i]!="\0"; i++){
		for(j=0; str2[j]!="\0"; j++){
			str[i+j]=str2[j];
		}
	str[i+j]="\0";
	}
}
```




//=函数的调用和返回

```c
fun(){}

fun();

fun(){
	return 0;
}
```



//函数的嵌套调用

在一个函数体内调用另一个函数。

```c
void fun1(){
	//.....
}

void fun2(){
	fun1();
}


```

//函数的递归调用

函数自已调用自已


注:

```c
int p       变量
int *p      指针
int **p    指向指针的指针    注意:通常用表现为指向数组的指针
```



//内部函数和外部函数

内部函数,又称为静态函数。只在当前源文件中调用,不被其它源文件调用。
static fun();

外部函数,是可以被其它源文件函数调用的函数。
extern fun();




//局部变量和全局变量

局部变量:函数体内变量称为局部变量,只在函数体内有效。

全局变量:在全局程序中有效的变量。



//常用标准函数库

```c
绝对值函数:
abs();
labs();
fabs();

三角函数:
sin();
cos();
tan();

字符判别函数:
isalpha();
isdigit();
isalnum();

字符串处理函数:
strcpy();
strcat();
strcmp();
strupr();
strlwr();
```



========================================================	





### 11 指针

```c
int a = 6;      //变量
int *p =&a;     //取变量 a 的内存地址; 


注:

int p        变量
int *p      指针
int **p     指向指针的指针    注意:通常用表现为指向数组的指针
```



//==指针的相关概念
//==地址与指针



内存的原理:

取变量i   找到地址,  占了4个内存单元,4个字节,  把地址放到CPU的寄存器中,最后通过cpu进行逻辑运算。

变量                              地址       内容

变量i    -------------->   1000        0
		                  1001
  		   	     1002
	                          1003	 

  

首先要定义指针:
int *p;
int a;

*p = &a;

&a //取得内存的地址;
*p  //取得内存地址的变量内容;



================================

```c
#include<stdio.h>

int main(){
	int i;
	int *p;

	scanf("%d",&i);
	
	p = &i;
	
	printf("%x\n",*p);
	return  0;

}
```



==================================
注:复习写法!!!

```c
int i;
int *p;

scanf("%d",&i);

p=&i;
printf("%s\n",*p);
return 0;


```

//==指针的自增自减

```c
int i,*ar[10]l;
i = &ar[0];  //第一个索引;
```

============================
这是一个写法,变量数组。

```c
#include<stdio.h>

int main(){
	int ar[5];
	int *q;
	int i;

	for(i=0; i<5; i++){
		ar[i];
	}
	
	q = &ar;
	
	printf("%d\n",q);      //1703708
	
	printf("%d\n",q+1);  //1703712
	
	printf("%d\n",q+2);  //1703716
	
	return 0;

}
```


//==二维数组与指针



```c
&a[0][0]    &a[0][1]   &a[0][2]   &a[0][3]   &a[0][4]
a[0]+0      a[0]+1      a[0]+2      a[0]+3     a[0]+4     

a
&a[0]

a+1 
&a[1]

a+2
&a[2]


```


//==字符串与指针

访问字符串的两种方式:
1,使用字符串
2,使用字符指针

1,

```c
char ar[] = "abckde";
printf("%s\n",ar);
```

2,
注意:指针数组不需要声明;

```c
#include<stdio.h>

int main(){
	char *str = "abckde";
	printf("%s",str);
	return 0;
}
```

//==指针数组

字符数组是  一维数组;
指针数组是  字符串为数组元素的数组;

注:为了更好的优化内存,减少内存中字节的占有数量;
5个字符的字符串,再加了末尾的\0, 长度占用内存字节6个,而内存中就要用20个字节给这个字符串,这会浪费内存的占有资源。所以这时要用到指针数组。

demo:

```c
#include<stdio.h>

int main(){
	int i;
	char *ar[] = {"aa","bb","cc","dd"};
	for(i=0; i<4; i++){
		printf("%s\n",ar[i]);
	}
	return 0;

}
```



//==指向指针的指针


指针指向另一个指针的指针。

```c
i(&i)->p1(&p1)->p2



int **p;
```






数组名,是内存中数组地址的首地址。

```c
int a[10]
for(){
	print("%d",*(p+i))
}


for(){
	print("%d",*p++)
}

p=a
```

两者是一样的。获取的变量值是相同的。
但是,*p++  要注意移动指针到首地址。p=a 方便再去写其它的需求。





//==指针变量作函数参数

1,形参为整数变量的,交换的是形参的值,而实参未改变。
2,形参为指针变量的,可以通过改变形参指针变量指向的值,来间接改变实参指向的值。



//==返回指针的函数和指向函数的指针

```c
定义:
int *fun(int x, int y);

调用
fun(a,b);

函数体:
int *fun(int a,int b){
	//函数体
}
```



//==指针数组作main函数的参数

```c
//主入口函数
main(int argc,char *argv){
	//方法体
}


```





### 12  结构体和共用体   类似PHP中的对象。

```c
struct Pro {
	char Name[10];
	char shap[10];
	char color[10];
	char cfunc[10];
	int iPrice;
}


struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
}


```



//==定义结构体

```c
demo:

#include<stdio.h>
//==结构体
struct Books{
	char title[50];
	char author[50];
	char subject[100];
}

int main(){
	

	return 0;

}
```






//==结构体变量定义

```c
struct Books{              //声明结构体 struct 
	char title[50];
	char author[50];
	char subject[100];
}
struct Books books1;  //声明结构体变量
struct Books books2; 

或者
struct Books{              //声明结构体 struct 
	char title[50];
	char author[50];
	char subject[100];
}boos1, books2;


```




//==结构体变量的引用         结构体变量名.成员名;

```c
books1.title;
books2.title="修改后的标题";


```



//==结构体类型的初始化

```c
struct Books{                                 //声明结构体 struct 
	char title[50];
	char author[50];
	char subject[100];
}books1 = {"biaoti","作者",1000}     //声明结构体变量并做类型初始化
struct Books books1;                     //声明结构体变量
struct Books books2; 


```


//==定义结构体数组

//结构体数组:

```c

           name   age   sex   

ar[0]
ar[1]
ar[2]
ar[3]
ar[4]
```


//内存中结构体数组的存储形式:

```
ar[0]         name1 
	age1
	sex1
ar[1]         name2
	age2
	sex2
ar[2]         name3
	age3
	sex3
```

//定义结构体数组:

```
struct Books{                                 //声明结构体 struct 
	char title[50];
	char author[50];
	char subject[100];
}Books[5];


```

//初始化结构体数组

```
struct Books{                                 //声明结构体 struct 
	char title[50];
	char author[50];
	char subject[100];

}Books = {                                    //初始化结构体数组
	{"titel1","author1",subject1}	
	{"titel2","author2",subject2},
	{"titel3","author3",subject3},
	{"titel4","author4",subject4},
	{"titel5","author5",subject5},
}
```



//==结构体指针

//指向结构体变量的指针

指向结构体变量的指针,指向的是结构体变量的首地址;

```
struct Student *pstruct;


```

//声明定义结构体指针

```
struct Books *bname;  //结构体指针
```

//调用结构体成员,使用结构体成员。

```
//方法1
(*bname).title;
(*bname).title = "wulei";

//方法2
bname->title="wulei"l;
```



//==指向结构体数组的指针


注:指向结构体数组的指针指向的是内存中的数组首地址!请注意!!!!

```
//定义结构体指针
struct Books *books1;
//结构体指向结构体数组
book1=Books;

//调用结构体成员,使用结构体成员。
//方法1
(*bname).title;
(*bname).title = "wulei";

//方法2
bname->title="wulei";
```



//==结构体在函数中的使用

1 结构体的变量做为函数的参数
2 结构体指针作为函数的参数
3 结构体成员作为函数参数


1 结构体的变量做为函数的参数 demo:

```
#include<stdio.h>

struct Xs{
	char name[10];
	int age[3];
}xs={"wulei",30};


void Xss(struct Xs stu){    //函数中使用结构体的变量
	printf("%s正在学习\n",stu.name);
}

int main(){
	Xss(xs);   //函数中使用结构体的变量
	return 0;
}
```

2 结构体指针作为函数的参数

```
demo:

#include<stdio.h>

//需求学生姓名,成绩,显示。函数调用结构体的指针,节省调用结构体占用的内存空间开销;

//结构体
struct Student{
	char name[10];
	float cj[3];
}student={"wulei",60,50,90};

//函数
void Displaya(struct Student *sta){    //函数传入 定义的结构体的指针
	printf("以上是学生的成绩----\n");
	printf("他的成绩是:%.2f\n",sta->cj[2]);   //通过结构体的指针,去改变结构体的成员值
	sta->cj[2]=1000;    
}

//主入口方法
int main(){
	struct Student *stb=&student;   //引用结构体变量,传给结构体指针
	Displaya(stb);    //函数,传入结构体指针   
	printf("修改后的成绩是:%.2f\n",stb->cj[2]);   
	return 0;
}
```


3 结构体成员作为函数参数

```
Displaya(student=->cj[2]);  
```




//==使用函数返回结构体指针



//==嵌套的结构体

结构体的成员,也可以是结构体




//=== 链条

//=链条的相关操作



```
#include<stdio.h>
#include<stdlib.h>

/* 

 思考:从人类的视角,从上帝的视角,从整体方面,从细节方面 

 1,实例化对象来考虑这个需求
 2,数据处理中数据的角度
 3,实现数据处理中的逻辑部分

*/
```



//=链接

```
malloc(); //在内存中动态分配一块size大小的内存空间
calloc(); //在内存中动态分配N个长度的size连续内存空间(连续)
free(); //释放指针指向的内存区域
```

===================================

```
#include<stdio.h>
#include<stdlib.h>


//结构体
struct Student
{
    char cName[20];							     	    /*姓名*/
    int iNumber;								    /*学号*/
    struct Student* pNext;							    /*指向下一个结点的指针*/
};


//增加新链条的动作
int iCount;								/*全局变量表示链表长度*/
struct Student* Create()
{
    struct Student* pHead=NULL;						    /*初始化链表头指针为空*/
    struct Student* pEnd,*pNew;
    iCount=0;								    /*初始化链表长度*/
    pEnd=pNew=(struct Student*)malloc(sizeof(struct Student));
    printf("请输入名字、学号:\n");
    scanf("%s",&pNew->cName);
    scanf("%d",&pNew->iNumber);

    while(pNew->iNumber!=0)
    {
        iCount++;
        if(iCount==1)
        {
            pNew->pNext=pHead;	    /*使得指向为空*/
            pEnd=pNew;							     /*跟踪新加入的结点*/
            pHead=pNew;							     /*头指针指向首结点*/
        }
        else
        {
            pNew->pNext=NULL;		/*新结点的指针为空*/
            pEnd->pNext=pNew;		/*原来的尾结点指向新结点*/
            pEnd=pNew;						     	       /*pEnd指向新结点*/
        }
        pNew=(struct Student*)malloc(sizeof(struct Student));	/*再次分配结点内存空间*/
        scanf("%s",&pNew->cName);
        scanf("%d",&pNew->iNumber);
    }
    free(pNew);								       /*释放没有用到的空间*/
    return pHead;

}


////显示这个链接 输出节点
void Print(struct Student* pHead)
{
    struct Student *pTemp;	/*循环所用的临时指针*/
    int iIndex=1;								    /*表示链表中结点的序号*/
    printf("----有 %d 个成员:----\n",iCount);	/*消息提示*/
    printf("\n");								    /*换行*/
    pTemp=pHead;								    /*指针得到首结点的地址*/
    while(pTemp!=NULL)
    {
        printf("NO%d 成员:\n",iIndex);
        printf("姓名: %s\n",pTemp->cName);	   /*输出姓名*/
        printf("学号: %d\n",pTemp->iNumber); /*输出学号*/
        printf("\n");								        /*输出换行*/
        pTemp=pTemp->pNext; /*移动临时指针到下一个结点*/
        iIndex++;							    	        /*进行自加运算*/
    }
}


//主入口函数
int main()
{
    struct Student* pHead;							    /*定义头结点*/
    pHead=Create();								    /*创建结点*/
    Print(pHead);							    	    /*输出链表*/
    return 0; 
    /*程序结束*/
}


```


//==共用体

```
union name{
	char name;
	int age;
	//成员列表
}

union name.name;
```

结构体:数据成员的大小的总和
共用体:数据成员的最大内存长度的大小

```
union name{
	char name;
	int age;
	//成员列表
}

union name.name;
```



结构体:数据成员的大小的总和
共用体:数据成员的最大内存长度的大小


demo1:

```
#include "stdio.h"
#include <string.h>


  /*声明公交车结构体类型*/ 
  struct bus 
  {
    char name[64];
  };

  /* 声明地铁结构体类型*/
  struct plane 
  {
    char name[64];
  };

  /*声明共用体类型*/
  union Transportation 
  {
   struct bus p;
   struct plane c;
  };
int main()
{
 union Transportation t;/*定义一个共用体*/
  strcpy(t.p.name, "地铁");/*将相应的名字复制给相应的变量*/
  strcpy(t.c.name, "公交车");
  printf("员工选择%s\n",t.p.name);/*输出信息*/
  printf("员工选择%s\n",t.c.name);
  return 0;
}
```

=========================================

demo2:

```
#include<stdio.h>

union DataUnion			/*声明共用体类型*/
{
	int iInt;								/*成员变量*/
	char cChar;			
};

int main()
{
	union DataUnion Union={97};		/*定义共用体变量,并进行初始化*/
	printf("iInt: %d\n",Union.iInt);		/*输出成员变量数据*/
	printf("cChar: %c\n",Union.cChar);
	return 0;
}
```

==========================================
//结构体

```
struct Student
{
	char cName[20];	/*姓名*/
	int iNumber;	/*学号*/
	struct Student* pNext; /*指向下一个节点的指针*/
};


int iCount;								/*全局变量表示链表长度*/
```

//新建链表节点

```
struct Student* Create()
{
	struct Student* pHead=NULL;			/*初始化链表,头指针为空*/
	struct Student* pEnd,*pNew;         /*尾和新加节点*/
	iCount=0;	                         /*初始化链表长度*/

	pEnd=pNew=(struct Student*)malloc(sizeof(struct Student));  /* 建内存空间大小 */


​	

	/* 输入链条的数据内容 */
	printf("请输入姓名、学号:\n");
	scanf("%s",&pNew->cName);
	scanf("%d",&pNew->iNumber);
	
	/* 新加的链条不等于0 也就是说 */
	while(pNew->iNumber!=0)
	{
		iCount++;
		if(iCount==1)
		{
			pNew->pNext=pHead;						/*使得指向为空*/
			pEnd=pNew;								/*跟踪新加入的节点*/
			pHead=pNew;								/*头指针指向首节点*/
		}
		else
		{
			pNew->pNext=NULL;						/*新节点的指针为空*/
			pEnd->pNext=pNew;						/*原来的尾节点指向新节点*/
			pEnd=pNew;								/*pEnd指向新节点*/
		}
	
		 /*再次分配节点内存空间*/
		pNew=(struct Student*)malloc(sizeof(struct Student));	
	                          
		scanf("%s",&pNew->cName);
		scanf("%d",&pNew->iNumber);
	}
	
	free(pNew);										/*释放没有用到的空间 返回头部*/
	return pHead;      

}
```

//输出链条节点 要写临时的指针 参数是 pHead 头。

```
void Print(struct Student* pHead)
{
	struct Student *pTemp;						/*循环所用的临时指针*/
	int iIndex=1;								/*表示链表中节点的序号*/

	printf("----有 %d 名成员:----\n",iCount);	/*消息提示*/
	printf("\n");								/*换行*/
	pTemp=pHead;								/*指针得到首节点的地址*/
	
	while(pTemp!=NULL)
	{
		printf(" NO%d 号成员:\n",iIndex);
		printf("姓名: %s\n",pTemp->cName);	/*输出姓名*/
		printf("学号: %d\n",pTemp->iNumber);	/*输出学号*/
		printf("\n"); /*输出换行*/
		pTemp=pTemp->pNext;  /*移动临时指针到下一个节点*/
		iIndex++;	 /*进行自加运算*/
	}

}
```

//插入链表节点

```
struct Student* Insert(struct Student* pHead)
{
	struct Student* pNew;						                /*指向新分配的空间*/
	printf("----插入第1名信息----\n");	/*提示信息*/

	/*分配内存空间,并返回指向该内存空间的指针*/
	pNew=(struct Student*)malloc(sizeof(struct Student));	


	/* 输入姓名和学号 */
	scanf("%s",&pNew->cName);
	scanf("%d",&pNew->iNumber);
	
	pNew->pNext=pHead;						/*新节点指针指向原来的首节点*/
	pHead=pNew;								/*头指针指向新节点*/
	iCount++;								/*增加链表节点数量*/
	
	return pHead;

}
```

//删除链表节点

```
void Delete(struct Student* pHead,int iIndex)
/*pHead表示头节点,iIndex表示要删除的节点下标*/
{
	int i;  									/*控制循环变量*/
	struct Student* pTemp;		 				/*临时指针*/
	struct Student* pPre;							/*表示要删除节点前的节点*/
	pTemp=pHead;								/*得到头节点*/
	pPre=pTemp;

	printf("----删除 NO%d 名成员----\n",iIndex); /*提示信息*/
	for(i=1;i<iIndex;i++)	 /*for循环使得pTemp指向要删除的节点*/
	{
		pPre=pTemp;
		pTemp=pTemp->pNext;
	}
	pPre->pNext=pTemp->pNext;	/*连接删除节点两边的节点*/
	free(pTemp);		/*释放要删除节点的内存空间*/
	iCount--;		                /*减少链表中的元素个数*/

}

//主入口
int main()
{
	struct Student* pHead;	/*定义头节点*/
	pHead=Create();		/*创建节点*/
	pHead=Insert(pHead);	/*插入节点*/
	Delete(pHead,2);		/*删除第二个节点*/
	Print(pHead);		/*输出链表*/
	return 0;			/*程序结束*/
}
```






//==枚举类型

注:不能被拆分;

```
enum name(na,ag,red=1);

enum name(na,ag,red=1) name; //定义枚举类型,并赋初始化。


```



//= typedef关键字

主要作用就是,为数据类型定义一个新的名字。简化结构体的名字

```
typedef struct Student {
	char *name;
	int age;
} STU;

STU  为这个结构体 重命名;
同时可以 

STU data;
```





//=== 位运算

在线进制转换器:
https://tool.oschina.net/hexconvert/

进制转换器:
https://tool.ip138.com/hexconvert/

C语言可以代替汇编语言,因为其支持二进制按位运算。

数据在内存中是以二进制的形式存放的。

一个字节 由 8位 二进制数组成。 8位占一个字节。

8bit

11001010

byte(8-bits)

1,按位与运算符
2,按位或运算符
3,按位取返运算符
4,按位异或运算符
5,左移运算符
6,右移运算符

1,按位与运算符

1&1 = 1
1&0 = 0
0&1 = 0

     0000000001011001  十进制89

&  0000000000100110  十进制38
     0000000000000000  十进制0

```
#include<stdio.h>								/*包含头文件*/
void main()									/*主函数main*/
{
    unsigned result; 	/*定义无符号变量*/
    int age1, age2; 	/*定义变量*/
    printf("请输入第一个人年龄age1:");/*提示输入年龄1*/
    scanf("%d",&age1); 	/*输入年龄1*/
    printf("请输入第二个人年龄age2:"); /*提示输入年龄2*/
    scanf("%d",&age2); /*输入年龄2*/
    printf("age1=%d, age2=%d", age1, age2); /*显示年龄*/
    result = age1&age2; /*计算"与"运算的结果*/
    printf("\nage1&age2=%u\n", result); 	/*输出计算结果*/
}
```



2,按位或运算符

1|1 = 1
1|0 = 1
0|1 = 1
0|0 = 0

   0000000000010001
|  0000000000011111
   0000000000011111

```
#include<stdio.h>           /*包含头文件*/
int main()                  /*主函数main*/
{
    int a=0xEFCA,result;    /*定义变量*/
    result = a|a;  /*计算或运算的结果*/
    printf("a|a=%X\n", result);	/*输出结果*/
    return 0;                    	/*程序结束*/
}


```

3,按位取返运算符

```
#include<stdio.h>								/*包含头文件*/
void main()/*主函数main*/
{
    unsigned result; 	/*定义无符号变量*/
    int a; 		/*定义变量*/
    printf("please input a:"); 	/*提示输入一个数*/
    scanf("%d",&a); 	/*输入数据*/
    printf("a=%d", a);	 /*显示输入的数据*/
    result = ~a;  	/*求a的反 ~   shift + `  */
    printf("\n~a=%o\n", result); 	/*显示结果*/
}
```



4,按位异或运算符

0^0 = 0
0^1 = 1
1^0 = 1
1^1 = 0

```
#include<stdio.h>
main()
{
    unsigned result; 								/*定义无符号数*/
    int a, b;
    printf("please input a:");
    scanf("%d",&a);
    printf("please input b:");
    scanf("%d",&b);
    printf("a=%d,b=%d", a, b);
    result = a^b; 									/*求a与b"异或"的结果*/
    printf("\na^b=%u\n", result);
}
```





5,左移运算符



a<<2  向左移2位

00000000000000000000000000100111
00000000000000000000000010011100

```
#include<stdio.h>
main()
{
	int x=15;
	x=x<<2; 	/*x左移两位*/
	printf("左移2的结果:%d\n",x);
	x=x<<3; 	/*x左移3位*/
	printf("再左移3的结果:%d\n",x);
}


```


6,右移运算符


a >> 2 向右移动





//循环移位

                  32-n  
                               n

x   |                      |=====|   

x   |=====|                      |  

1, y = x>> (32-n)
2, y = x>> n
3, y = y|z



```
#include <stdio.h>
left(unsigned value, int n)/*自定义左移函数*/
{
    unsigned z;
    z = (value >> (32-n)) | (value << n);	/*循环左移的实现过程*/
    return z;
} 
int main()
{
    unsigned a;
    int n;
    printf("请输入一个数:\n");
    scanf("%o", &a);	/*输入一个八进制数*/
    printf("请输入要移位的位数(>0):\n");
    scanf("%d", &n);	/*输入要移位的位数*/
    printf("循环左移的结果:%o\n", left(a, n));	/*将左移后的结果输出*/
	return 0;
}
```





//位段


一种特殊的结构体类型,结构体中的成员被称为位段。

```
struct name {


}
```





### 13 预处理命令

程序在编译之前进行的处理;

//宏定义 #开头的代码。 
只是用于字符的替换,不分配内存空间。

1,不带参数的  #define命令
2,带参数的  #define命令
3,宏定义的删除  #undef命令
4,预定义宏简介


1,不带参数的  #define命令  行尾可不加 ; 号

//用于字符的替换,不分配内存空间。

#define TEST "替换的代码内宏"  

可以用 #undef TEST 结束宏定;

```
void fun(){
	printf();
	#undef TEST 
} 


```

2,带参数的  #define命令

//用于字符的替换,不分配内存空间。

```
#include<stdio.h>
#define MIX(a,b) ((a)*(b)+(b))	/*宏定义求两个数的混合运算*/
main()
{
	int x=5,y=9;
	printf("x,y:\n");
	printf("%d,%d\n",x,y);
	/*宏定义调用*/
	printf("the min number is:%d\n",MIX(x,y));
}
```


3,宏定义的删除  #undef命令

```
#include<stdio.h>
#define TEST

void fun(){
	printf();
	#undef TEST  //宏定义的删除
} 
```



4,预定义宏简介

__LINE__
__FILE__
__DATE__
__TIME__
__STDC__



//文件包含

#include<stdio.h> //库函数使用

#include "fun.h"   //自定义函数使用

如果希望其中一部分代码编译,只在满足一定条件下才进行编译,就需要使用条件编译命令。




//条件编译


#if
#else
#elif
#endif

判断宏名是否被定义

#ifdef
#ifndef


//其他预处理命令

#line
#error
#pragma





### 14 文件

文件是一组相关数据的有序集合

//=文件基本操作

//文件指针


FILE *fp;


//打开文件

FILE *fp;
fopen("1.txt","r");


//关闭文件

FILE *fp;
fopen("1.txt","r");
fclose(fp);


//=文件读写

打开文件后可以对文件进行读写。

//写入字符

FILE *fp;
fputc("内容",fp);

注: exit(0);

==================

```
#include<stdio.h>
#include<stdlib.h>
int main()
{
    FILE *fp; /*定义一个指向FILE类型结构体的指针变量*/
    char ch; /*定义变量为字符型*/
    if((fp = fopen("E:\\exp01.txt", "w")) == NULL) /*以只写方式打开指定文件*/
    {
        printf("不能打开文件\n");
        exit(0);
    }
    printf("请输入名人名言:\n");
    ch = getchar();	/*getchar函数带回一个字符赋予ch*/
    while(ch != '#')/*当输入"#"时结束循环*/
    {
        fputc(ch, fp);	/*将读入的字符写到磁盘文件中*/
        ch = getchar();	/*getchar函数继续带回一个字符赋给ch*/
    }
    fclose(fp);	/*关闭文件*/
	return 0;
}


```

//读取字符

fgetc();

注意:在C语言循环中输出字符后,通常还需要再次调用fgetc函数是为了确保读取到文件末尾。‌ 

```
#include<stdio.h>
int main()
{
    FILE *fp;	/*定义一个指向FILE类型结构体的指针变量*/
    char ch;	/*定义变量及数组为字符型*/
    fp = fopen("H:\\poem.txt", "r"); /*以只读方式打开指定文件*/
    ch = fgetc(fp); /*fgetc函数带回一个字符赋予ch*/

    while(ch != EOF)	/*当读入的字符值等于EOF时结束循环*/
    {
        putchar(ch);	/*将读入的字符输出到屏幕上*/
        ch = fgetc(fp);	/*fgetc函数继续带回一个字符赋予ch*/
    }
    printf("\n");
    fclose(fp);  /*关闭文件*/
    return 0;

}
```






//写入字符串

```
fputs();


#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE *fp;
	char filename[30],str[30];							/*定义两个字符型数组*/
	printf("请输入文件路径:\n");
	scanf("%s",filename);	 /*输入文件名*/
	if((fp=fopen(filename,"w"))==NULL)/*判断文件是否打开失败*/
	{
		printf("不能打开文件!\n请按任意键结束\n");
		getchar();
		exit(0);
	}
	printf("请输入歌词:\n");/*提示输入字符串*/
	getchar();
	gets(str);
	fputs(str,fp); /*将字符串写入fp所指向的文件中*/
	fclose(fp);
	return 0;
}


```

//读取字符串

fgets(字符数组,n,文件指针);
注:n表示读取的字符串的个数, sizeOf(name); 

```
#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE *fp;
	char filename[30],str[30]; /*定义两个字符型数组*/
	printf("请输入文件路径:\n");
	scanf("%s",filename);	  /*输入文件名*/
	if((fp=fopen(filename,"r"))==NULL) /*判断文件是否打开失败*/
	{
		printf("不能打开文件!\n请按任意键结束\n");
		getchar();
		exit(0);
	}
	fgets(str,sizeof(str),fp); /*读取磁盘文件中的内容*/
	printf("%s",str);
	printf("\n");
	fclose(fp);
	return 0;
}
```

//对磁盘文件格式化函数
//fprintf();
//fscanf();






//读写数据块

实际开发中,往往需要对整块数据进行读写,例如对一个结构体的变量进行读写。

fread();
fwrite();





```
#include<stdio.h>
#include<stdlib.h>
struct student_list									/*定义结构体,存储实习生基本信息*/
{
    char name[10];
    char adr[20];
    char tel[15];
} info[100];
void save(char *name, int n)	/*自定义save函数*/
{
    FILE *fp;	/*定义一个指向FILE类型结构体的指针变量*/
    int i;
    if((fp = fopen(name, "wb")) == NULL)/*以只写方式打开指定文件*/
    {
        printf("不能打开文件\n");
        exit(0);
    }
    for(i = 0; i < n; i++)
        if(fwrite(&info[i], sizeof(struct student_list), 1, fp) != 1)	/*将一组数据输出到fp所指的文件中*/
            printf("写入有误\n");	/*如果写入文件不成功,则输出错误*/
    fclose(fp);		/*关闭文件*/
}
void show(char *name, int n)/*自定义show函数*/
{
    int i;
    FILE *fp;	/*定义一个指向FILE类型结构体的指针变量*/
    if((fp = fopen(name, "rb")) == NULL)/*以只读方式打开指定文件*/
    {
        printf("不能打开文件\n");
        exit(0);
    } 
    for(i = 0; i < n; i++)
    {
        fread(&info[i], sizeof(struct student_list), 1, fp);	/*从fp所指向的文件读入数据存到info数组中*/
        printf("%15s%20s%20s\n", info[i].name, info[i].adr,info[i].tel);
    }
    fclose(fp);	/*关闭文件*/
}
int main()
{
    int i, n;/*变量类型为基本整型*/
    char filename[50];	/*数组为字符型*/
    printf("一共几名?\n");
    scanf("%d", &n);	/*输入实习生数*/
    printf("请输入文件路径:\n");
    scanf("%s", filename);	/*输入文件所在路径及名称*/
    printf("请输入姓名,地址,手机号\n");
    for (i = 0; i < n; i++)	/*输入实习生信息*/
    {
        printf("NO%d", i + 1);
        scanf("%s%s%s", info[i].name, info[i].adr, info[i].tel);
        save(filename, n);	/*调用函数save*/
    }
	printf("信息如下:\n");
    show(filename, n);	/*调用函数show*/
}
```











//=文件定位

对文件操作时,往往不需要从文件首开始,只操作指定内容即可,这时,就需要使用文件定位函数。


fseek(文件类型指针,位移量,起始点);  //移动文件内部的位置指针
rewind(文件类型指针);  //指针返回文件首。
ftell(文件类型指针); //得到流式文件的当前位置



fseek(fp,7L,0);   // 7L 是移动7个字节

```
#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE *fp;
	char filename[30],str[50]; /*定义两个字符型数组*/
	printf("请输入文件路径:\n");
	scanf("%s",filename); /*输入文件名*/
	if((fp=fopen(filename,"wb"))==NULL) /*判断文件是否打开失败*/
	{
		printf("不能打开文件!\n请按任意键继续\n");
		getchar();
		exit(0);
	}
	printf("请输入字符串:\n");
	getchar();
	gets(str);
	fputs(str,fp);
	fclose(fp);
	if((fp=fopen(filename,"rb"))==NULL) /*判断文件是否打开失败*/
	{
		printf("不能打开文件!\n请按任意键继续\n");
		getchar();
		exit(0);
	}
	fseek(fp,7L,0);
	fgets(str,sizeof(str),fp);
	printf("\n取货号为:\n");
	puts(str);
	fclose(fp);
    return 0;
}


```




rewind(文件类型指针);   //指针返回到文件首。

```
#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE *fp;
	char ch,filename[50];
	printf("请输入文件路径:\n");
	scanf("%s",filename);	/*输入文件名*/						 
	if((fp=fopen(filename,"r"))==NULL) 	/*以只读方式打开该文件*/			 
	{
		printf("不能打开文件\n");
		exit(0);
	}
	printf("\n输入密码:\n");
	ch = fgetc(fp);				
	while (ch != EOF)				
	{
		putchar(ch);/*输出字符*/							 
		ch = fgetc(fp); /*获取fp指向文件中的字符*/							 
	}

	rewind(fp);/*指针指向文件开头*/
	printf("\n请再次输入密码:\n");
	ch = fgetc(fp);			
	while (ch != EOF)					
	{
		putchar(ch); /*输出字符*/							 
		ch = fgetc(fp);			
	}
	printf("\n");
	fclose(fp); 	/*关闭文件*/								 
	return 0;

}
```



ftell(文件类型指针); //得到流式文件当前位置。



```
#include<stdio.h>
#include<stdlib.h>
int main()
{
		FILE *fp; 	/*定义一个指向FILE类型结构体的指针变量*/
		int n;
		char ch,filename[50];
		printf("请输入文件路径:\n");
		scanf("%s",filename);	 /*输入文件位置*/ 
		if((fp=fopen(filename,"r"))==NULL) /*判断是否能打开文件*/ 
		{
			printf("不能打开此文件\n");
			exit(0);
		}
		printf("密码为:");
		ch = fgetc(fp);	/*读出一个字符*/
		while (ch != EOF)				
		{
			putchar(ch);								 
			ch = fgetc(fp); 						 
		}
			n=ftell(fp);/*输出长度*/
    	if(6==n)	/*判断长度是否等于6*/
			printf("\n设置密码成功\n");
    	else
			printf("\n设置密码失败\n");
		fclose(fp); 	/*关闭文件*/		 
      return 0;
}
```



//=文件管理

//删除文件 remove();
//重命名文件 rename();
//复制文件




//删除文件 remove();



```
#include<stdio.h>
#include<stdlib.h>
int main()
{
    FILE *fp; /*定义一个指向FILE类型结构体的指针变量*/
    char filename[50];	/*定义数组为字符型*/
    printf("请输入要删除的文件名称:\n");
    scanf("%s", filename);	/*输入要删除的文件的路径及名称*/
    if ((fp = fopen(filename, "r")) != NULL)/*以只读方式打开指定文件*/
    {
        printf("%s 打开成功!", filename);/*文件打开成功输出提示信息*/
        fclose(fp);	/*关闭文件*/
    }
    else
    {
        printf("%s 不能打开!", filename);/*文件打开失败输出提示信息*/
        exit(0);
    }
    remove(filename);/*调用函数删除文件*/
    if ((fp = fopen(filename, "r")) == NULL)
        printf("\n%s 文件已被删除!", filename);	/*若要打开的文件不存在,则删除成功,输出提示信息*/
    else
        printf("错误");	/*若要打开的文件存在,则删除不成功,输出提示信息*/
}
```






//重命名文件 rename();



```
#include<stdio.h>
#include<stdlib.h>
int main()
{
    FILE *fp;/*定义一个指向FILE类型结构体的指针变量*/
    char filename1[20], filename2[20];/*定义数组为字符型*/

    printf("请输入要重命名的文件:\n");
    
    scanf("%s", filename1);	/*输入要重命名的文件所在的路径及名称*/
    
    if ((fp = fopen(filename1, "r")) != NULL)/*以只读方式打开指定文件*/
    {
        printf("%s 打开成功", filename1);
        printf("\n请输入新名字!");
    
    	scanf("%s", filename2);	/*输入新的文件路径及名称*/
    
    	fclose(fp);
    
        if(rename(filename1, filename2) == 0)
        	printf("已经把文件 %s 修改为 %s.\n",filename1,filename2);
        else
        	perror("rename");
    }
    else
    {
        printf("不能打开!");
        exit(0);
    }

}
```







//复制文件
把要复制的,放到临时字符串中,再把要复制的,写入到新文件中,再读出内容。

```
#include<stdio.h>
#include<stdlib.h>
int main()
{
    FILE *in,*out;	/*定义两个指向FILE类型结构体的指针变量*/
    char ch, infile[50], outfile[50];	/*定义数组及变量为基本整型*/
    printf("要被复制的文件名称:\n");
    scanf("%s", infile);/*输入将要被复制的文件所在路径及名称*/
    printf("输入复制出的文件名称:\n");
    scanf("%s", outfile);/*输入新建的将用于复制的文件所在路径及名称*/
    if ((in = fopen(infile, "r")) == NULL)/*以只写方式打开指定文件*/
    {
        printf("不能打开被复制文件\n");
        exit(0);
    }
    if ((out = fopen(outfile, "w")) == NULL)
    {
        printf("不能打开复制出的文件\n");
        exit(0);
    }
    ch = fgetc(in);
    while (ch != EOF)
    {
        fputc(ch, out);	/*将in指向的文件的内容复制到out所指向的文件中*/
        ch = fgetc(in);
    }
    fclose(in);
    fclose(out);
}
```










//=文件状态检测

//文件读取结束检测 feof();
//文件读写出错检测 ferror();
//清除状态标志 clearerr();



//文件读取结束检测 feof();



```c
#include <stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	char a;
	while ((a = fgetc(pf)) != EOF)    //fgetc读取文件时,读取失败返回EOF
	{
		putchar(a);
	}
	if (feof(pf) == 0)
	{
		printf("遇到文件末尾\n");

	}
	else
		printf("文件读取失败\n");
	fclose(pf);
	pf = NULL;
	return 0;

}
```






//文件读写出错检测 ferror();





```c
#include <stdio.h>
int main() {
	FILE *file;
	char c;
	int ret;
	file = fopen("test.txt", "r");
	fputc('A', file);
	if (ferror(file)) {
		perror("文件file发生错误");
	}
	return 0;
}
```





//清除状态标志 clearerr();

```c
#include <stdio.h>
int main(void) {
	FILE *file;
	char c;
	int ret;
	file = fopen("test.txt", "r");
	fputc('A', file);
	if (ferror(file)) {
		perror("写入文件发生错误");
	}
	clearerr(file);//清除文件的错误标志
	c = fgetc(file);
	printf("c=%c\n", c);
	if (ferror(file)) {
		perror("写入文件发生错误");
	}
	return 0;
}
```







### 15 内存管理


内存模型示意图:


1, 程序代码区        【静态数据区】    存储在内存的固定位置

2, 常量                  【静态数据区】    存储在内存的固定位置

      未初始化的变量  【静态数据区】    存储在内存的固定位置
    
      已初始化的变量  【静态数据区】    存储在内存的固定位置

3, 堆区  【堆区的内存池中】   动态数据区需要内存动态分配

4, 栈区  【栈区的内存池中】   局部数据对象,函数,以及调用的函数,被调用的函数







### 16 网络套接字编程

包括IP地址,OSI七层参考模型,地址解析,域名系统,TCP/IP协义端口,熟悉套接字的内容。


//=计算机网络基础

//iP地址
//OSI七层参考模型
//地址解析
//域名解析
//TCP/IP协义端口
//端口
//套接字引入
//网络字节顺序




//=套接字基础

服务端:
1,创建套接字
2,套接字绑定IP 端口
3,设置套接字的状态,准备接收客户端的请求
4,接收请求,同时返回一个用于连接的新套接字
5,使用新套接字,进行通信
6,通信完毕,释放套接字


客户端:
1,创建套接字
2,向服务器发出连接请求
3,连接后,与服务器进行通信操作
4,释放套接字。


//套接字的概述
//基于TCP的socket编程
//基于UDP的socket编程



//=套接字函数
//套接字常用函数介绍
//基于TCP的网络聊天程序

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注