### 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的网络聊天程序