c语言

article/2025/9/24 6:25:37

C语言笔记

程序员除了素质一无所有

纯手工打造

独具匠心

Mr_zhang

  • 访问此博客

  • 好评
  • 非常好评
  • 极度好评

文章目录

  • C语言笔记
        • 访问此博客
        • linux常用命令:
        • 文件夹权限说明:
        • vi编辑器:
            • C语言编译过程:预处理-----编译-----汇编-----链接
            • 寄存器是CPU内部最小的存储单位
          • 原码反码补码:
        • break作用:
      • 数组
      • 数组名
      • 求三个数最大值
      • 求数组最大值
      • 数组翻转
      • 冒泡排序
      • 多维数组
      • 二维数组数组名
      • 二维数组平均分
      • 字符数组
      • 字符数组初始化
      • 随机数产生
      • scanf_字符串输入
      • gets
      • fgets
      • puts
      • fputs
      • strlen
      • 字符串拷贝
      • 字符串比较
      • sprintf
      • ssanf
      • 字符串查询
      • 字符串切割
      • 无参无返回值函数
      • 有参无返回值
      • 无参有返回值
      • return 和 exit
      • 声明和定义的区别
    • 指针
      • 野指针:这个指针变量保存了一个没有意义(非法)的地址
      • 空指
      • 指针大小
      • 多级指针
          • [ ]不是数组专属
      • 万能指针
      • 指针步长
      • const修饰的指针
      • 指向数组首元素的指针
      • 通过指针加法访问指针元素
        • 指针数组
      • 值传递
      • 地址传递
      • 形参中的数组
      • 返回局部变量地址
      • 返回全局变量的地址
      • 字符串打印
      • 字符指针
      • 字符串拷贝
      • 字符串拷贝函数
      • 文字常量去不能修改
      • 字符串赋值和常量
      • main函数形参使用说明
      • 查找匹配字符串出现次数
      • 两头堵模型
    • 普通局部变量
    • static局部变量
      • 普通局部变量和static局部变量区别:
      • 普通全局变量(外部链接)
        • 普通全局变量的定义和声明:
      • static全局变量(内部链接)
        • 普通函数和static函数的区别
      • 普通局部变量
      • static局部变量
      • 普通全局变量
      • c语言全局变量缺陷
      • 全局变量分文件
        • main.c
        • test.c
        • test.h
        • 内存加载
          • ulimit -a : linux查看栈空间
      • 栈越界
      • 内存操作函数 memset()使用
      • memcpy
      • 内存重叠
      • 比较memcmp
    • 生成一个适合你的列表
    • 创建一个表格
      • 设定内容居中、居左、居右
      • SmartyPants
    • 创建一个自定义列表
    • 如何创建一个注脚
    • 注释也是必不可少的
    • KaTeX数学公式
    • 新的甘特图功能,丰富你的文章
    • UML 图表
    • FLowchart流程图
    • 导出与导入
      • 导出
      • 导入

  • linux目录结构:
    /:根目录
    /bin: /usr/bin:可执行二进制文件的目录
    /lib: /usr/local/lib:系统使用的函数库的目录
    /home:系统默认的用户家目录
    /usr/include:头文件所在的目录

  • 文件分类:普通文件,目录文件,设备文件,管道文件,链接文件
    文件权限:访问用户,访问权限
    访问用户:文件所有者,用户组,其他用户
    访问权限:读权限(r),写权限(w),可执行权限(x)

linux常用命令:

  1. 查看帮助文档:* --help , man * 手册
  2. 查看文件信息:ls -a所有 -l详细 -h人性化
  3. 输出重定向命令:>
  4. 分屏显示:more
  5. 管道:|
  6. 清屏:clear
  7. 切换工作目录:cd
  8. 显示当前路径:pwd
  9. 创建目录:mkdir
  10. 创建文件 :touch
  11. 删除文件 :rm
  12. 建立链接文件:ln -s软链接
  13. 查看文件内容:cat
  14. 文本搜索:grep
  15. 查找文件:find
  16. 拷贝文件:cp -r文件夹
  17. 移动文件:mv
  18. 获取文件类型:file
  19. 归档管理:tar
  20. 文件压缩解压:gzip -cvf 压缩 -xvf 解压
  21. 文件压缩解压:bzip2
  22. 查看命令位置:which

  • 软链接:
    1.类似于windows的快捷方式,软链接依赖于源文件存在
    2.如果源文件删除,软链接没有意义

  • tar只负责打包,解包,不进行压缩
    打包:tar -cvf xxx.tar 需要打包的文件
    解包:tar -xvf xxx.tar 需要解包的文件
    指定目录解包:tar -xvf xxx.tar -C 指定路径目录

  • 如何查看某个目录的大小:
    du ./目录 -h

  • gzip压缩tar包
    压缩:gzip [-r] xxx.tar 自动在当前目录生成:xxx.tar.gz
    解压:gzip [-d] xxx.tar
    压缩打包:
    tar -czvf xxx.tar.gz 所需文件
    bzip2压缩tar包
    压缩:bzip2 [-r] xxx.tar 自动在当前目录生成:xxx.tar.bz2
    解压:bzip2 [-d] xxx.tar
    bzip2压缩打包:
    tar -cjvf xxx.tar.dz2
    解压解包:tar -xjvf xxx.tar.dz2

  • 创建新用户:
    useradd -d /home/名称 用户名 -m
    更改密码:passwd 用户名

  • 曾登陆用户时间历史:last


创建一个用户(系统默认创建一个用户组,这个用户组的名字和用户的名字是一样的)
查看用户信息:cat /zhang/passwd
zhang:x:1000:1000:zhang,:home/zhang:/bin/bash
第一个1000代表是用户id
第二个1000代表是这个用户属于哪个组,组id


更改权限:chmod
chmod 777(4 2 1)文件名 可读可写可执行 r 4 w 2 x 1
u 所有者 g 用户 o 其他用户
chmod u+w 文件名

文件夹权限说明:

x:没有此权限,不允许用户进入
r:没有这个权限,无法查看文件夹的内容
w: 没有这个权限,无法新建和删除文件
查看当前日历:cal
显示或者设置时间:date
查看进程信息:ps -a显示终端的所有进程,包括其他用户的进程 -u显示进程的详细状态
-x 显示没有控制终端的进程
ps -aux | grep xxx 利用管道查询进程
杀死进程:kill -9强制杀死进程
动态进程:top
重启:reboot , init 6i
关机:shutdown now , init 0
查看或配置网卡信息:ifconfig


vi编辑器:

进入插入模式:i
退出插入模式:Esc
:wq 保存并退出
:q!强制退出
:x给文件加密码
:!命令 暂时离开vi,执行命令
i 光标位置当前处插入文字
o光标位置下方开启新行
O光标位置上方开启新行
I光标所在行首插入文字
A光标所在行尾插入文字
dd 从当前行剪切(删除)
yy 从当前行复制
p粘贴
u 撤销
gg去第一行句首
G去最后一行句首
xgg去指定一行句首
/xxx 在vi中查找xxx
n下一个
N上一个
:set nu 设定行号
:set nonu 取消行号

在linux下,指向用户编译的可执行程序,如果没有配置环境,在当前路径前面必须加 ./
system:
功能:在已经运行的程序中执行另外一个外部程序
参数:外部可执行程序的名字
返回值:不同系统返回值不一样
字符编码:
window默认支持的中文编码为gbk,gb2312,ANSI
linux默认支持的中文编码为 UTF-8

只在windows有效:我们使用的是windows命令
calc 计算器
mspaint 画图板
notepad 记事本
windows图形界面只有两个:Qt,MFC(微软vs)
vs中C语言可以嵌套汇编代码

C语言编译过程:预处理-----编译-----汇编-----链接
  1. 预处理:宏定义展开,头文件展开,条件编译等,同时将代码的注释删除,这里并不会检查语法
  2. 编译:检查语法,将预处理后文件生成汇编文件
  3. 汇编:将汇编文件生成目标文件(二进制文件)
  4. 链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去
    分布编译:
    预处理:gcc -E hello.c -o hello.i
    编 译 :gcc -S hello.i -o hello.s
    汇编 :gcc -c hello.s -o hello.o
    链接 :gcc hello.o -o hello_elf

交换文件说明:
1.vi写文件,没有保存就关闭,自动生成一个后缀为.swp交换文件,保存了前面写的内容
2.先恢复,再删除

寄存器是CPU内部最小的存储单位
  1. 如果需要运算,不能在内存中直接运算
  2. 如果需要运算,把内存中的数据加载到寄存器,在运算
  3. 把运算结果从寄存器移回内存中

数据类型的作用:告诉编译器定义这么一个类型的变量需要分配多大的空间
变量在使用前必须先定义,定义变量前必须有相应的数据类型
标识符命名规则:
标识符不能是关键字
标识符只能由字母,数字,下划线组成
第一个字符必须为字母或下划线
标识符中字母区分大小写
1Byte=8bit
%d : 以10进制的方式打印
%o :以8进制的方式打印
%x :以16进制的方式打印
int a=123 //以十进制方式赋值
int a=0123 //以八进制的方式赋值
int a=0xABC //以十六进制方式赋值


原码反码补码:

(1)存储1字节(8位)大小的数字(char)
原码(用户角度):原始的二进制
1.用户的数字分为正负数,符号位的存储
2.最高位为符号位:0代表为正数,1代表为负数
3.1000 0001 左边是最高位,右边是低位

+1 :0000 0001
-1 :1000 0001
+0 :0000 0000
-0 :1000 0000

原码存储导致2个问题:
1.0有两种存储方式
2.正数和负数相加,结果不正确(计算机只会加不会减)

以原码的方式来算:

反码(为了算补码)
0.正数的原码和反码是一样的
1.求原码
2.在原码的基础上,符号位不变,其他位取反(0为1,1为0)
+1 :0000 0001
-1 :1111 1110
+0 :0111 1111
-0 :1111 1111
反码存储导致1个问题:
1.0有两种存储方式(0不分正负,只有一种存储方式)

以反码的方式计算:
1 - 1 = 1 + (-1)
1 : 0000 0001
-1 : 1111 1110
1111 1111 = -0
计算机存储数字以补码方式存储(为了解决负数的存储)

补码:
1.正数的原码,反码,补码都一样
2.补码为其反码+1

+1 :0000 0001
-1 :1111 1111
+0 :0111 1111
-0 :1 0000 0000(因为8位,所以最高为丢弃) =0000 0000

以补码的方式来算:
1-1 = 1 + (-1)
1: 0000 0001
-1: 1111 1111
1 0000 0000 = 0
//0x81转化为二进制1000 0001,最高位为1,说明是负数

char a = 0x81;
printf("%d\n",a);

结果是 -127
补码:1000 0001
反码:1111 1110
原码:1111 1111 = -127

char类型为1字节(8位)范围:有符号: -128~127 无符号:0~255
-0系统当成 -128
%x,系统默认以4字节(32位)大小打印
%d,以有符号来打印
%u,以无符号来打印
赋值或运算,不能越界

sizeof的功能是计算一个数据类型的大小,单位为字节
int占4个字节 short占2个字节
字符型(char)
1.内存中没有字符,只有数字
2.一个数字,对应的一个字符,这种规则叫做ASCII
3.使用字符或数字给字符变量赋值是等价的

4.字符类型本质上就是1个字节大小的整形
逻辑运算符
!(逻辑非) :如果a为假,则!a为真,如果a为真,则!a为假
&&(逻辑与) :如果a和b都为真,则结果为真,否则为假
||(逻辑或) :如果a和b有一个为真,则结果为真,二者都为假时,结果为假

运算符和表达式
1.相除得到小数问题
a)两个整数相除,只是取整数,不会带小数

int a=1/2; // a=0

b)要想得到小数的结果,分子分母至少有一个是小数

 double aa=1.0/2;// a=0.5a=1/(double)2;

死循环
//{ }可以不写,不写只有第一个语句属于循环

while1{}

//{ }必须写,语法

do
{}while(1)

//{ }可以不写,不写只有第一个语句属于循环

for(;;)
{}

循环的嵌套:任何一个循环的内部可以调用其他的循环

while()
{while(){do{for(){while(){}}    }while();}
}

int i=0;
int j=0;
int num=0;

/*
1.i=0;
2.判断i<10的条件,条件为真,执行for(j=0;j<10;j++){}内容,条件为假,跳出循环
3.执行{}内部

*/

for(i=0;i<10;i++)
{
for(j=0;j<10;j++)
{
num++;
}

}

break作用:

1.跳出switch语句
2.跳出循环
3.如果有多个循环,跳出最近的内循环
continue:属于循环,跳出本次循环,下次继续
goto:任意地方都可以使用,无条件跳转,勿滥用

数组

#include<stdio.h>
int main()
{
int a;//定义一个普通变量
//1.同一个{}内部,数组名不能和其他变量,其他数组名同名
//2.定义数组,[]最好是常量
int n=10;
int b[n];
//3.使用数组时,[]里 可以是变量,可以是常量,也可以是表达式
}int main01()
{
//1.定义一个数组,数组内部有10个int类型的元素(变量)
//2.定义数组和定义变量的区别,名字后面加[],[]里面写元素个数
//3.数组在内存中是连续存储的
//4.通过下标访问数组的元素,下标从0开始,从0到9,没有a[10]这个元素
//5.有多少个[]就是多少维
int array[10];
array[0]=0;
array[1]=1;
array[2]=2;
}
  1. 编译器不是我们想象中那么智能,有些错误不能立马呈现
    错误:
  2. 编译错误(语法出错)
  3. 运行时错误(运行时异常),有些错误不能立马呈现

[ ]内部的变量或数组,不初始化,它的值为随机数

数组名

# include <stdio.h>
int main()
{
int a[10];
/*1.数组名是常量,不能修改*/
/*2.数组名的地址是数组首元素的地址*/
printf("a=%p,&a[0]=%p",a,&a[0]);
/*3.sizeof(数组名)测数组总大小 :10(元素)*4(一个元素4个字节)=40*/
printf("sizeof(a)=%lu\n",sizeof(a));
};

求三个数最大值

#include<stdio.h>
int main()
{int a=10;int b=20;int c=30;int max;max=a>b?a:b;printf("max=%d\n",max);max=(a>b?a:b)>c?(a>b?a:b):c;
printf("max=%d\n",max);return 0;
}int main01()
{int a=10;int b=20;int c=30;int max;if(a>b)
{max=a;
}else if
{max=b;
}
if(max>c)
{printf("最大值为%d\n",max);
}else
{printf("最大值为%d\n",c); 
}
}

求数组最大值

#include<stdio.h>
int main()
{int a[]={10,-1,20,3,5,9,1,6,50,6};int n=sizeof(a)/sizeof(a[0]);int max=a[0];int i=0;for(i=1;i<n;i++){if(a[i]>max)
{max=a[i];
}
}
printf("数组最大值为%d\n",max);
return 0;}

数组翻转

Alt text

#include<stdio.h>
int main()
{int a[]={1,2,3,4,5,6,7,8,9};int n=sizeof(a)/sizeof(a[0]);  /*元素个数*/int i=0;     /*首元素下标*/int j=n-1;  /*尾元素下标*/int tmp;while(i<j){/*交换a[i]和a[j]*/tmp=a[i];a[i]=a[j];a[j]=tmp;i++;   /*从左往右*/j--;   /*从右忘左*/}
for(i=0;i<n;i++)
{printf("%d",a[i]);
}
printf("\n");
}

冒泡排序

![Alt text](./Image 1.png)

#include <stdio.h>
int main()
{int a[]={1,-1,2,-2,3,-3,4,-4,5,-5};int n=sizeof(a)/sizeof(a[0]);int i=0;int j=0;int tmp;
printf("排序前");for(i=0;i<n;i++)
{printf("%d",a[i]);
}printf("\n");for(i=0;i<n-1;i++){for(j=0;j<n-1-i;j++){if(a[j]>a[j+1]){tmp=a[j];a[j]=a[j+1];a[j+1]=tmp;
}
}
}
printf("排序后");
for(i=1;i<n;i++)
{printf("排序后:%d",a[i]);
}
printf("\n");}

多维数组

#include<stdio.h>
int main()
{/*1、有多少[]就有多少维2、内存中没有多维,都只有一维,多维数组是特殊的一维数组3、定义了一个一维数组a[3],这个一位数组有3个元素,每个元素int[4]4、a[0],a[1],a[2]就是第0,1,2,元素的数组名5、二维数组用户可以理解为m行n列
*/
int a[3][4];
int i=0;
int j=0;
int num=0;
for(i=0;i<3;i++)
{for(j=0;j<4;j++)
{a[i][j]=num;num++;
}
}for(i=0;i<3;i++)
{for(j=0;j<4;j++){printf("%d ,",a[i][j]);}
printf("\n");
}}

二维数组数组名

#include<stdio.h>
int main()
{int a[5][10];
//1.数组名是常量,不能修改
//2.sizeof(数组名),测数组的总大小:5*int[10]=5*4*10=200
printf("sizeof(a)=%lu\n",sizeof(a));
//3.sizeof(a[0]),测的是第0个元素的大小:int [10]=4*10=40
printf("sizeof(a[0])=%lu\n",sizeof(a[0]));//求行数(元素个数):总大小/每个元素的大小
int n=sizeof(a)/sizeof(a[0]);
printf("n1=%d\n");
//求列数
n=sizeof(a[0])/sizeof(int);
printf("n2=%d\n",n);
//行*列
n=sizeof(a)/sizeof(a[0])*sizeof(a[0])/sizeof(int)=sizeof(a)/sizeof(int);printf("n3=%d\n",n);}

二维数组平均分

#include<stdio.h>
int main()
{int a[5][3]=
{{30,60,80,},{60,60,60},{77,88,99,},{88,66,77},{12,22,8}
};int i=0;int j=0;int sum =0;for(i=0;i<3;i++){sum=0;for(j=0;j<5;j++){sum+=a[j][i];}
}
printf("平均分:%lf\n",sum/5.0);
}

字符数组

#include <stdio.h>
int main ()
{/*1、C语言没有字符串类型,用字符数组模拟2、字符串一定是字符数组,字符数组不一定是字符串3、如果字符数组以字符'\0'('\0'等价于0)结尾,那么这个字符数组就是字符串*/char a[10];char b[]={'a','b','c'};/*字符数组*/char c[10]={'a','b','c','\0'};/*字符串*/
return 0;}

字符数组初始化

#include <stdio.h>
int main()
{char a1[]={'a','b','c'};/*字符数组*/printf("a1=%s\n",a1);/*乱码,因为没有结束符*/char a2[]={'a','b','c',0};/*字符串*/printf("a2=%s\n",a2);char a3[]={'a','b','c','\0'};
printf("a3=%s\n",a3);char a4[]={'a','b','c','\0','h','e'};
printf("a4=%s\n",a4);/*abc*/char a5[10]={'a','b','c'};/*前3个字符赋值为a,b,c,后面自动赋值为0*/
printf("a5=%s\n",a5);/*常用初始化,使用字符串初始化,在字符串结尾自动加数字0*/
char a7[10]="abc";
printf("a7=%s\n",a7");char a8[10]="abc";
printf("sizeof(a8)=%lu\n",sizeof(a8));/*字符串自动隐藏一个字符*/char a9[10]="\0abc";
printf("a9=%s\n",a9);/*\0后面最好别跟数字,有可能组成一个转义字符,'012'就是'\n'*/
char a10[10]="\012abc";
printf("a10=%s\n",a10);}
sizeof()测数据类型大小,不会因为结束符提前结束char a[100];
scanf("%s",a);
//a没有&,原因数组名是首元素地址,本来就是地址
printf("a=%s\n",a);

随机数产生

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main ()
{/*先设置种子,种子设置一次即可如果srand()参数一样,随机数就一样srand(100);time(NULL)功能获取系统当前时间,由于时间会变,srand()也会改变
*/srand(        (unsigned int) time(NULL)     );int i=0;int num;for(i=0;i<100;i++){num=rand();printf("num=%d\n",num);}
return 0;
}

scanf_字符串输入

![Alt text](./Image 2.png)


#include<stdio.h>
int main()
{char buf[100]={0};printf("请输入字符串buf:");scanf("%s", buf);/*不需要&,默认以空格分开*/printf("buf=%s\n",buf);char tmp[100]={0};printf("请输入字符串tmp:");scanf("%s", tmp);/*不需要&,默认以空格分开*/printf("tmp=%s\n",tmp);/*scanf()的缺陷,不做越界检查,此函数不安全*/char str[100]={0};printf("请输入字符串str:");scanf("%s", str);/*不需要&,默认以空格分开*/printf("str=%s\n",str);}

gets

#include <stdio.h>
int main()
{char buf[100];/*gets()从键盘读取字符串,放在指定数组gets()允许有空格,不做越界检查,此函数不安全*/gets(buf);printf("buf=%s\n",buf);return 0}

fgets

#include<stdio.h>
int main()
{char buf[100];/*从stdin(代表标准输入,键盘),读取内容如果输入内容如果大于sizeof(buf)-1,只取sizeof(buf)-1,放在buf所在的数组会把换行符也读进去*/fgets(buf,sizeof(buf), stdin);printf("buf=%s\n",buf);return 0; 
}

puts

#include <stdio.h>
int main()
{char buf[]="hello";
/*把buf内容输出到屏幕,自动在屏幕加换行,是在屏幕加,字符串本身没有变量*/puts(buf);printf("%s",buf);
}

fputs

#include <stdio.h>
int main()
{char buf[]="hello";
/*往stdout(代表屏幕,标准输出)输出buf内容*/fputs(buf,stdout);}

strlen

#include <stdio.h>
#include <string.h>
int main()
{char buf[]="hello";/*strlen需要使用返回值,返回值就是字符串长度从首元素开始,到结束符为止的长度,结束符不算(遇到'\0'结束)
*/int len=strlen(buf);printf("len=%d\n",len);
/*多了一个结束符\0*/printf("sizeof(buf)=%lu\n",sizeof(buf));char buf2="\0hello";len=strlen(buf2);printf("len2=%d\n",len);/*sizeof()测数据类型的长度,不会因为结束符提前结束*/printf("sizeof(buf2)=%lu\n",sizeof(buf2));char str[100]="mike";printf("strlen(str)=%lu\n",strlen(str));printf("sizeof(str)=%lu\n",sizeof(str));return 0;
}

字符串拷贝

#include<stdio.h>
#include<string.h>
int main()
{char src[100]="hello\0 mike";char dst[100]="aaaaaaaaaaa";/*功能:把src字符数组前12个字符的内容拷贝给dst所代表的数组*/
strncpy(dst,src,sizeof(src));printf("dst=%s\n",dst);
printf("dst=%s\n",dst+strlen("hello")+1);return 0;
}
int main02()
{char src[100]="hello\0 mike";char dst[100];/*功能:把str字符数组前8个字符的内容拷贝给dst所代表的数组
*/
strncpy(dst,src,8);printf("dst=%s\n",dst);
printf("dst=%s\n",dst+7);return 0;
}
int main01()
{char src[100]="hello mike";char dst[100];/*功能:把src字符数组的内容拷贝给dst所代表的数组拷贝原理,从首元素开始,遇到结束符'\0'结束
*/strcpy(dst,src);printf("dst=%s\n",dst);char src2[100]="hello\0 mike";char dst2[100]strcpy(dst2,src2);printf("dst2=%s\n",dst);return 0;
}

字符串比较

#include<stdio.h>
int main()
{char s1[]="abc";char s2[]="abcd";int flag=strcmp(s1,s2);
/*指定比较前3个字符首先比较第一个字符,只要第一个字符大于对方,就已经比对方大int flag=strncmp(s1,s2,3);
*/if(flag>0)
{printf("[%s]>[%s]\n",s1,s2);
}
else if(flag<0)
{printf("[%s]<[%s]\n",s1,s2);
}
else
{printf("[%s]==[%s]\n",s1,s2);
}
}

sprintf

#include <stdio.h>
int main()
{int a=10;char ch='b';char buf[]="hello";
/*格式化一个字符串,把这个字符串输出到屏幕*/printf("a=%d,ch=%c,buf=%s\n",a,ch,buf);/*格式化一个字符串,把这个字符输出(保存)指定的数组*/char dst[100];sprintf(dst,"a=%d,ch=%c,buf=%s\n"a,ch,buf);printf(@@%s@@,dst);
}

ssanf

#include <stdio.h>
int main()
{
char buf[]="1 2 3";int a,b,c;
/*从buf中以指定的格式提取内容*/sscanf(buf,"%d %d %d",&a,&b,&c);printf("a=%d,b=%d,c=%d\n",a,b,c);/*提取整形最方便*/char str[]="a=1,b=2,c=3";a=0;b=0;c=0;sscanf(str,"a=%d,b=%d,c=%d",&a,&b,&c);printf("a1=%d,b1=%d,c1=%d\n",a,b,c);char str2[]="1,2,3";
a=0;b=0;c=0;
sscanf(str2,"a=%d,b=%d,c=%d",&a,&b,&c);
printf("a2=%d,b2=%d,c3=%d\n",a,b,c);/*提取字符串,默认以空格分隔,可以提取*/
char tmp[]="abc mike 250";
char m[10],n[10];k[10];
/*不用&,数组名就是首元素地址*/sscanf(tmp,"%s %s %s",m,n,k);
printf("m=%s, n=%s, k=%s\n",m,n,k);char tmp1[]="abc,mike,250";
char m1[10],n1[10];k1[10];
/*不用&,数组名就是首元素地址*/
sscanf(tmp1,"%s,%s,%s",m1,n1,k1);
printf("m1=%s, n1=%s, k1=%s\n",m1,n1,k1);return 0;}
int main01 ()
{int a ,b c ;printf("请输入三个数");scanf("%d %d %d",&a,&b,&c);printf("a=%d,b=$d,c=%d\n",a,b,c);return 0;
}

字符串查询

#include<stdio.h>
#include <string.h>
int main()
{
char buf[]="abcdefg"
/*在buf中查询字符d,如果找到,返回d所在位置的地址如果查询失败,返回NULL*/char *p=strchr(buf,'b');
if(p==NULL)
{printf("查询失败\n");
}
else
{
printf("p=%s\n",p);
}}

字符串切割

#include<stdio.h>
#include<string.h>
int main()
{char buf[]="abc,mike,250";char tmo[];strcpy(tmp,buf);char *p=strtok(tmp,",");while(p!=NULL)
{printf("p=%s\n",p);p=strtop(NULL,",");
}
}
int main01()
{char buf[]="abc,mike,250";char tmp[];strcpy(tmp,buf);/*第一次调用第一次参数写源字符串,第二次参数写切割字符返回值就是切割后的字符串在匹配切割字符的地方,换成结束符使用strtok()会破坏原来字符串的结构如果没有切割成功,返回NULL
*/
printf("before,buf[3]=%d\n",buf[3]);
char *p=strtok(tmp,",");
/*第二次调用,第一个参数需要写NULL*/
p=strtok(NULL,",");
printf("p2=%s\n",p);printf("p=%s\n",p);printf("buf=%s\n",buf);printf("buf[3]=%d\n",buf[3]);
return 0;
}
  • 无参无返回值函数

#include <stdio.h>
void fun ()/*等价于void fun(void)*/
{/*无参无返回值函数的定义1、没有返回值,用void关键字修饰2、没有参数,也可以用void,或者为空3、第一个void代表返回值,fun代表函数名字,()内部代表参数,空就是无参,{}就是函数体4、同一个文件不能出现同名函数5、不同的函数,内部的变量是没有关系的函数内部,包括()内部的变量,只有在调用时分配空间,调用完毕自动释放
*/
printf("我是无参无返回值函数的定义\n");int a=10;int b=20;printf("a+b=%d\n",a+b);
}
int main()
{/*1、除了main函数外,其他函数只有调用了才起作用2、函数的调用不可能出现void关键字3、无参无返回值函数的调用格式:函数名字()
*/fun();
return 0}
  • 有参无返回值

#include <stdio.h>
/*
有参无返回值函数的定义1、定义函数的参数就做形参,形参的格式必须为:类型+变量,不能赋值2、函数没有调用,形参变量不会分配空间,函数调用完毕,形参变量自动释放
*/void fun1(int a)
{printf("a=%d\n",a);
}
/*如果形参有多个,用逗号","隔开*/void fun2(int a,char ch,char buf[100])
{printf("a=%d,ch=%c,buf=%s\n",a,ch,buf);
}int main()
{int a =10;
/*
有参无返回值函数的调用1、如果函数定义室友参数,调用时必须传参2、有参函数调用形式:函数名(匹配类型参数)3、匹配类型参数可以是变量,常量,表达式4、函数调用时传的参数,叫做实参5、只能把实参的值传递给形参,不能反过来,单向传递
*/fun1(10);int i=11;fun1=(i);fun1(1>2);/*6、函数的形参有多个,传参也用逗号","隔开*/fun2(10,'a',"hello");}
  • 无参有返回值

#include<stdio.h>
/*
无参有返回值函数的定义1、第一个int代表函数的返回类型,函数内部通过return返回2、return作用终止当前的函数3、返回值可以是常量,变量,表达式
*/
int fun()
{return 10;   /*返回常量*/
}int fun1()
{int a=11;return a;   /*返回变量*/
}int fun2()
{int a=10int b=20;return a>b?a:b;   /*返回表达式*/
}
/*
4、函数返回值只能返回一个,不能返回多个
5、如果return的类型和函数返回类型不一致,以函数返回类型为准
*/
int fun3()
{return 9.5555;
}
int main()
{
/*
1、如果函数有返回值,这个返回值可以不用2、如果使用返回值,最好要定义匹配类型的变量来接收/
*/fun(); int a=fun();
printf("a=%d\n",a);int b;b=fun();printf("b=%d\n",b);printf("tmp=%d\n",fun());printf("fun1=%d\n",fun1());printf("fun2=%d\n",fun2());printf("fun3=%d\n",fun3);return 0;
}

return 和 exit

#include <stdio.h>
#include <stdlib.h>
int fun()
{printf("fun\n");exit(250;  /*结束整个程序,结束进程*/
}
/*return主函数(main),程序结束return其他函数,程序不结束
*/
int main()
{while(1){}
return 0;  /*return作用:中断函数,中断main,程序就结束*/
printf("main\n");
}

声明和定义的区别

#include <stdio.h>
/*1. 编译器很笨,在main函数调用其他函数,只会往前找函数的定义2. 如果找不到函数的定义,就找函数的声明,如果没有声明,c编译器会警告,c++会出错3. 如果没有定义,直接调用一个不存在的函数,会报错4. 如果定义没有放在main函数前面,那么在调用前需要声明,声明加不加extern是一样的5. 一个函数只能定义一次,可以声明多次6. 声明的形参变量名和定义的形参变量名可以不一样7. 可以只声明,不定义函数(无意义),此函数不能调用
*/
/*函数的声明,告诉编译器,这个函数是有意义的,只是放在别的地方*/int my_strlen(char buf[]);
/*8、声明时,形参变量名可以不写,可以只写类型,定义时,形参变量名一定要写*/void fun(int a,int, int);int main()
{printf("len=%d\n",my_strlen("0123456789"));return 0;
}
int my_strlen(char str[])
{int i=0;while(str[i]!='\0')
{i++;
}
return i;
}

指针

![Alt text](./Image 3.png)

![Alt text](./Image 4.png)

#include <stdio.h>
int main()
{
/*
1、指针也是一个变量2、p是一个变量,p的类型是int *
*/ int *p;
p=123;
printf("%d\n",p);/*2、指针指向谁,就把谁的地址赋值给指针*/
int a=10;
p=&a;  /*p保存了a的地址*/
/*%p打印地址,是以16进制方式来打印*/
printf("%p, %p\n",p,&a);/*
3、直接操作指针变量本身没有意义
4、需要操作*p,操作指针所指向的内存
*/
*p=100;   /**p相当于a*/
printf("%d, %d\n",*p,a);return 0;}

![Alt text](./Image [5].png)

#include<stdio.h>
int main()
{int a=10;int *p=&a;*p=111;int *q;q=p;*q=222;printf("&a=%p,p=%p,q=%p\n",&a,p,q);printf("a=%d,*p=%d,*q=%d\n",a,*p,*q);return 0;
}

野指针:这个指针变量保存了一个没有意义(非法)的地址

![Alt text](./Image [6].png)

#include <stdio.h>
int main()
{int *p;p=0x1234;printf("p=%d\n",p);
/**p=100;错误1、只有定义后的变量,此变量的地址才是合法地址2、野指针就是保存没有意义地址的指针变量3、操作野指针变量本身不会有任何问题4、操作野指针所指向的内存才导致段错误p=0x1234;没有定义0x1234;可能有一个叫0x1234的变量,*p=100就是操作这个0x1234变量,无法操作,所以出现段错误*/*p=100;return 0;}

空指

#include <stdio.h>
int main()
{/*1、空指针,就给指针变量赋值为NULL2、NULL就是数字0
*/int *p=NULL;int a=11;p=&a;if(p!=NULL)
{*p=100;
}return 0;
}

指针大小

#include <stdio.h>
int main()
{/*1、32位编译器用32位大小(4字节)保存地址2、64位编译器用64位大小(8字节)保存地址
*/int a=sizeof(int *);int b=sizeof(int *);double *p;int c=sizeof(p);printf("a=%d,b=%d,c=%d\n",a,b,c);return 0;
}

多级指针

![Alt text](./Image [7].png)

![Alt text](./Image [8].png)

[ ]不是数组专属
#include <stdio.h>
int main()
{int a=10;int *p=&a;/*通过指针简洁操作a的内存*/*p=111;printf("a=%d\n",a);printf("*p=%d\n",*p);
/* *p等价于*(p+0),同时等价于p[0]*/printf("p[0]=%d\n",p[0]);
/* *p等价于p[0],操作的是指针所指向的内存*/p[0]=250;printf("a2=%d\n",a);return 0;
}

万能指针

![Alt text](./Image [9].png)

#include <stdio.h>
int main()
{/*1、不可以定义void类型的普通变量,不能确定类型2、可以定义void *变量,void *指针也叫万能指针3、void *可以指向任何类型的变量
*/void *p=NULL;int a=10;p=&a;*((int *)p)=222;  /*只保存了a的首地址*/printf("*p=%d\n",*((int *)p));}

指针步长

#include <stdio.h>
int main()
{/*1、指针的加法,不是传统的加法2、步长由指针指向的数据类型决定
*/int a;int *p=&a;printf("p=%d,p+1=%d\n",p,p+1);char b;char *q=&b;printf("q=%d,q+1=%a\n",q,q+1);
}

const修饰的指针

#include <stdio.h>
int main()
{/*1、指针变量2、指针所指向的空间
*/int a =10;int *p1=&a;*p1=100;p1=NULL;/*const 修饰* ,代表指针所指向的内存是只读的*/const int *p2=&a;/* *p2=100;不能操作*/p2=NULL;/*const 修饰* ,代表指针所指向的内存是只读的*/int const *p3=&a;p3=NULL;/*const 修饰指针变量,代表指针变量的值为只读*/int * const p4=&a;*p4=100;/* p4=NULL; 不能操作*/ const int * const p4=&a;return 0;}

指向数组首元素的指针

![Alt text](./Image [10].png)

#include <stdio.h>
int main()
{int a[10]={1,2,3,4,5,6,7,8,9,10};int *p=NULL;
/*p指针变量指向首元素*/p=&a;p=a;int i=0;for (i=0;i<10;i++){printf("%d,",*(p+i));/*等价于printf("%d",a[i]);printf("%d",p[i]);p[i]等价于 *(p+i),操作都是指针所指向的内存
*/} printf("\n");
}

通过指针加法访问指针元素

#include <stdio.h>
int main()
{int a[10]={1,2,3,4,5,6,7,8,9,10};
/*定义一个指针,指向首元素*/int *p=&a[0];int n=sizeof(a)/sizeof(*a);int i=0;for(i=0;i<n;i++){printf("%d, ",*p);p++;
}printf("\n")/*定义一个指针,指向尾元素*/int *q=&a[n-1];q=a+n-1;for(i=0;i<n;i++)
{printf("%d, "*q);q--;
}
printf("\n");
}
  • ####指针数组,它是数组,每个元素都是指针
  • ####数组指针,它是指针,指向数组的指针

指针数组

![Alt text](./Image [11].png)

#include <stdio.h>
int main()
{int a[3]={0,1,2};/*指针数组,它是数组,每个元素都是指针*/int *p[3];p[0]=&a[0];p[0]=a;p[1]=&a[1];p[2]=&a[2];int n=sizeof(p)/sizeof(p[0]);int i=0;for(i=0;i<n;i++){p[i]=&a[i];
}for(i=0;i<n;i++){printf("%d\n",*p[i]);
}return 0;
}int main01()
{int a =10;int b =20;int c =30;int *p1=&a;int *p2=&b;int *p3=&c;return 0;
}

值传递

![Alt text](./Image [14].png)

#include <stdio.h>
void swap(int m,int n)
{int tmp;tmp=m;m=n;n=tmp;printf("m=%d,n=%d\n",m,n);
}
int main()
{int a=11;int b=22;swap(a,b);  /*值传递,形参的修改不会影响到实参*/printf("a=%d,b=%d\n",a,b);return 0;
}

地址传递

![Alt text](./Image [13].png)

#include <stdio.h>
void swap(int *m,int *n)
{
int tmp;
tmp=*m;
*m=*n;
*n=tmp;
printf("m=%d,n=%d\n",m,n);
}
int main()
{int a=11;
int b=22;
swap(&a,&b);  /*地址传递,变量的地址*/
printf("a=%d,b=%d\n",a,b);
return 0;
}

形参中的数组

#include <stdio.h>/*1、形参中的数组,不是数组,他是普通指针变量2、形参数组:int a[100000],int a[],int *a对编译器而已,没有任何区别3、编译器都是当作int *处理4、形参中的数组和非形参数组的区别:形参的数组是指针变量,非形参就是数组void printf_array(int a[100000])void printf_array(int *a)
*/void printf_array(int a[])
{int i=0;
/*64位系统,sizeof(a),a是指针变量,结果为8sizeof(a[0])第0个元素,是int类型,结果为4
*/int n=sizeof(a)/sizeof(a[0]);printf("sizeof(a):%d\n",sizeof(a));printf("sizeof(a[0]):%d\n",sizeof(a[0]));
for(i=0;i<n;i++)
{
printf("%d, ",a[i]);
}
printf("\n");a=NULL; /*形参中的数组,不是数组,它是普通指针变量*/
}int printf_array2(int a[0],int n){int i=0;for(i=0;i<n;i++){printf("%d, \n",a[i]);
}printf("\n");}int main()
{int a[]={1,-2,3,-4,5,-6,7,-8,9};int i=0;int n=sizeof(a)/sizeof(a[0]);printf_array2  (a,n);printf("排序前\n");/*冒泡排序*/int j=0;int tmp;for(i=0;i<n-1;i++){for(j=0;j<n-1-i;j++){if(a[j]>a[j+1]) {tmp=a[j];a[j]=a[j+1];a[j+1]=tmp;
}
}
}printf("排序后\n");for(i=0;i<n;i++){printf("%d, "a[i]); 
}printf("\n");return 0;
}

返回局部变量地址

![Alt text](./Image [14].png)

返回全局变量的地址

#include <stdio.h>
/*1、在{}外面定义的变量,就是全局变量,全局变量任何地方都能使用2、全局变量只有在整个程序结束后,才释放
*/
int a;
int *fun()
{return &a; /*fun()调用完毕,a不释放*/
}
int main()
{int *p=NULL;p=fun();*p=100;printf("*p=%d\n",*p);printf("a=%d\n",a);* ( fun() )=111;printf("a=%d\n",a);
}

字符串打印

#include <stdio.h>
int main()
{char str[]="hello mike";
/*1、%s,从首元素开始打印,直到结束符位置2、%s,操作的是指针所指向的内容printf("str=%s\n",str);
*//*2、str是首元素地址,如果想打印str本身的值,%p,%x,%d,%o
*/printf("str=%p\n",str);/*
3、*str代表第0个元素,它是char
*/printf("str3=%c\n",*str);int i=0;while( str[i]!='\0'){printf("%c",str[i]);i++;
}
printf("\n");
}

字符指针

![Alt text](./Image [15].png)

#include <stdio.h>
int main()
{char str[]="hello";str[0]='1';*(str+1)='2';printf("str=%s\n",str);   /*  12llo;*//*定义一个指针,指向首元素*/char *p=NULL;p=str[0];p=str;*p='a';p++;*p='b';printf("str=%s\n",str);  /* abllo*/printf("p=%s\n",p);   /*  bllo*/printf("p=%s\n",p-1);  /*abllo*/return 0;
}

字符串拷贝

#include <stdio.h>
int main()
{char buf[100];char *p=buf;/*p指向buf的首元素strcpy()是给p所指向的内存拷贝内容,字符串拷贝给了buf
*/ strcpy(p,"hello mike abc");printf("p=%s\n,buf=%s\n",p,buf);return 0;
}int main01()
{char p;/*错误1、不是给p变量拷贝内容2、给p所指向的内存拷贝内容3、p是野指针,给野指针所指向的内存拷贝内容,结果导致段错误
*/strcpy(p,"hello mike abc");
}

字符串拷贝函数

#include <stdio.h>
void my_strcpy(char *dst,char *src)
{int i=0;while(*(src+i)!='\0'){*(dst+i)=*(str+i);i++;
}/*结束符*/*(dst+i)=0;}
int main()
{char src[]="hello mike";char dst[100];my_strcpy(dst,src);printf("dst=%s\n",dst);
}

文字常量去不能修改

![Alt text](./Image [16].png)

#include <stdio.h>
int main()
{/*1、字符串常量就是此字符串的首元素地址*/printf("s1=%p\n","hello mike");char *p1="hello mike";printf("p=%p\n",p1);char *p2="hello mike";printf("p2=%p\n",p2);/*2、字符串常量,文字常量区的字符串,只读,不能修改*/printf("*p1=%c\n",*p1);/*字符串常量,文字常量区的字符串,只读,不能修改*p1='a';  err
*/
/*char *p3="hello ";p3指文字常量区,不能修改strcpy(p3,"abc");
*/main01();}
void fun()
{printf("fun s2=%p\n","hello mike");
}
int main01()
{/*1、每个字符串都是一个地址,这个地址是指字符串首元素地址2、字符串常量放在data区,文字常量区
*/printf("s1=%s\n","hello mike");printf("s1=%p\n","hello mike");printf("s3=%s\n","hello mike"+1);printf("s4=%c\n",*("hello mike"));fun();
}

字符串赋值和常量

![Alt text](./Image [17].png)

#include <stdio.h>
int main()
{/*1、p指针保存了"hello"的地址2、指针所指向的内存不能修改
*/char *p="hello";/*1、把"hello"一个一个字符放在buf数组中2、数组的元素可以修改
*/char buf[]="hello";return 0;
}

main函数形参使用说明

#include<stdio.h>
/*argc[]:它是数组,数组每个元素都是char*,每个元素都是字符地址argc:argc[]元素个数main()函数参数,需要用户传递
*/
int main(int argc,char *argc[])
{int i=0;for(i=0;i<argc;i++)
{printf("test=%s\n",argc[i])
}return 0;
}

查找匹配字符串出现次数

#include <stdio.h>
#include <string.h>
int main()
{char *p="11abcd11111122222abcd12666333abcd552652qqq";char i=0;char *tmp=NULL;while(1){/*查找匹配字符串,如果找到,返回匹配字符串的地址,没有返回空*/tmp=strstr(p,"abcd");if(tmp==NULL)  /*没有找到*/{break;  /*跳出循环*/
}else   /*找到*/{i++;   /*累加*//*重新设置寻找的起点*/p=tmp+strlen("abcd");
}
}printf("%s出现abcd的次数为:%d\n");return 0;
}

两头堵模型

#include <stdio.h>
#include <sr>
int main()
{char *p="      123456789     ";char *start=p;char *end=p+strlen(p)-1;while(*start==' '&&start!='\0'){start++;
}while(*end==' '&&end!=p){end--;
}int n=end-start+1;printf("n=%d\n",n);int buf[100]="aaaaaaaaaaa";buf[n]=0;  /*结束符*/strncpy(buf,start,n);printf("buf=%s\n",buf);
}
  • 普通局部变量

  1. 在{}内部定义的变量就是局部变量
  2. 只有执行到定义变量的这个语句,系统才会给这个变量分配空间
  3. 当离开{},这个非static局部自动释放
  4. 局部变量的作用域在当前的{},离开{},无法使用此变量
  5. {}的普通局部变量。加不加auto关键字等价,普通局部变量也叫自动变量
  6. 不同的{}中,变量名字可以一样
  7. 如果static局部变量不初始化,它的值默认为随机数
  • static局部变量

  1. 在{}内部定义的变量就是局部变量
  2. static局部变量,是在编译阶段就已经分配空间,函数没有调用前,它就已经存在
  3. 当离开{},这个非static局部自动释放
  4. 局部变量的作用域在当前的{},离开{},无法使用此变量
  5. {}的普通局部变量。加不加auto关键字等价,普通局部变量也叫自动变量
  6. 如果static局部变量不初始化,它的值默认为0
  7. static局部变量初始化语句,只会执行一次,但是可以赋值多次
  8. static变量只能用常量初始化
  • 普通局部变量和static局部变量区别:

  1. 内存分配和释放
    a)普通局部变量只有执行到定义变量的语句才分配空间
    b)static局部变量在编译阶段(函数还没有执行),变量的空间已经分配
    c)普通局部变量离开作用域{},自动释放
    d)static局部变量只有在整个程序结束才自动释放
  2. 初始化
    a)普通局部变量不初始化,值为随机数
    b)static局部变量不初始化,值为0
    c)static局部变量初始化语句只有第一次执行时有效
    d)static局部变量只能用常量初始化
  • 普通全局变量(外部链接)

  1. 在{}外面(函数外面)定义的变量为全局变量
  2. 只有定义了全局变量,任何地方都能使用此变量
  3. 如果使用变量时,在前面找不到此全局变量的定义,需要声明才能使用
  4. 全局变量不初始化,默认赋值为0
  5. 声明只是针对全局变量,不是针对局部变量=
  6. 全局变量只能定义一次,可以声明多次
  7. 全局变量在编译阶段已经分配空间(函数没有执行前),只有在整个程序结束,
    才自动释放
  8. 分文件中不同文件,普通全局变量只能定义一次,可以声明多次
  9. 不同文件,普通全局变量只能定义一次,可以声明多次
  • 普通全局变量的定义和声明:

  1. 定义一个全局变量,建议初始化
    int a=10;
  2. -如果声明一个全局变量,建议加extern
    extern int a;
  • static全局变量(内部链接)

a)static全局变量和普通全局变量的区别就是作用域不一样(文件作用域)
b)extern关键字只适用于普通全局变量
c)普通全局变量,所有文件都能使用,前提需要声明
d)static全局变量只能本文件使用,别的文件不能使用
c)不同文件只能出现一个普通全局变量的定义
d)一个文件只能有一个static全局变量的定义,不同文件间的static全局变量,就算名字相同,也是没有关系的两个变量

  • 普通函数和static函数的区别

a)所有文件只能有一次普通函数的定义
b)一个文件可以有一个static函数的定义
c)普通函数所有文件都能调用,前提是使用前声明
d)static函数只能在定义所在的文件中使用

  • 普通局部变量

#include <stdio.h>
int main()
{int a=10;if(1){int a=11;/*就近原则*/printf("a=%d\n",a);   /*a=11*/}/*1、if()的a只能在if{}中使用2、离开if{},if中的啊已经释放
*/printf("a=%d\n",a);
}
int main01()
{/*1、在{}内部定义的变量就是局部变量2、只有执行到定义变量的这个语句,系统才会给这个变量分配空间3、当离开{},这个非static局部自动释放4、局部变量的作用域在当前的{},离开{},无法使用此变量5、{}的普通局部变量。加不加auto关键字等价,普通局部变量也叫自动变量6、不同的{}中,变量名字可以一样7、如果static局部变量不初始化,它的值默认为随机数
*/int tmp=11;{int a=10;{a=11;  /*ok;还在作用域范围内*/}}/*a=11;  err; 离开作用域*/if(1){int b=10;}for(int i=0;i<10;i++){/*i只属于for语句,离开佛如就不能使用*/i=11;}/*printf("i=%d\n",i);
*/}

static局部变量

#include <stdio.h>
void fun()
{int i=0;i++;printf("fun i=%d\n",i);
}
void static_fun()
{
/*1、在{}内部定义的变量就是局部变量2、static局部变量,是在编译阶段就已经分配空间,函数没有调用前,它就已经存在3、当离开{},这个非static局部自动释放4、局部变量的作用域在当前的{},离开{},无法使用此变量5、{}的普通局部变量。加不加auto关键字等价,普通局部变量也叫自动变量6、如果static局部变量不初始化,它的值默认为07、static局部变量初始化语句,只会执行一次,但是可以赋值多次8、static变量只能用常量初始化
*/static int i=0;i++;printf("static_fun i=%d\n",i);
}int main(){fun();fun();fun();static_fun();static_fun();static_fun();
}

普通全局变量

#include<stdio.h>
/*
1、在{}外面(函数外面)定义的变量为全局变量
2、只有定义了全局变量,任何地方都能使用此变量
3、如果使用变量时,在前面找不到此全局变量的定义,需要声明才能使用
4、全局变量不初始化,默认赋值为0
5、声明只是针对全局变量,不是针对局部变量
6、全局变量只能定义一次,可以声明多次
7、全局变量在编译阶段已经分配空间(函数没有执行前),只有在整个程序结束,才自动释放
8、不同文件,普通全局变量只能定义一次,可以声明多次
*/
void fun2()
{extern int a;     /*声明时,不要赋值*/extern int a;extern int a;printf("fun2 a=%d\n",a);
}int a=10;
void fun()
{a=11;
}
int main()
{fun();printf("a=%d\n",a);fun2();}

c语言全局变量缺陷

#include<stdio.h>
int a;
int a;
int a=0;/*定义,其他是声明*/ 
int a;
int a;/*有一次是定义,有三次是声明*/
int b;
int b;
int b;
int b;/*
1、如果定义一个全局变量,没有赋值(初始化),无法确定是定义,还是声明
2、如果定义一个全局变量,同时初始化,这个肯定是定义
*/int main()
{/*只有声明,没有定义,无法给变量赋值extern int b=10;
*/b=10;printf("b=%d\n",b);
return 0;
}

全局变量分文件

  • main.c

#include "test.h"
int main()
{
/*
使用函数前,声明函数
声明函数,extern可有可无
声明可以多次
*/test();a=111;b=222;return 0;
}
  • test.c

int a=0;
int b=0;
void test()
{a=10;b=20;
}
  • test.h

/*各种声明*/
extern int a;
extern int b;
void test();

![Alt text](./Image [18].png)

内存加载

在程序没有执行前,有几个内存分区已经确定,虽然分区确定,但是没有加载内存,程序只有运行时才加载内存:
text(代码区):只读,函数
data:初始化的数据,全局变量,static变量,文字常量区去(只读)
bss:没有初始化的数据,全局变量,static变量

当运行程序,加载内存,首先根据前面确定的内存分区(text,data,bss)先加载,然后额外加载两个区
text(代码区):只读,函数
data:初始化的数据,全局变量,static变量,文字常量区去(只读)
bss:没有初始化的数据,全局变量,static变量
stack:(栈区):普通局部变量,自动管理内存,先进后出的特点
heap: (堆区):手动申请空间,手动释放,整个程序结束,系统也会自动 回收,如果没有手动释放,程序也没有结束,这个堆区空 间不会自动释放

![Alt text](./Image [19].png)

  • ulimit -a : linux查看栈空间

栈越界

#include<stdio.h>
int main()
{/*语法上没有问题,栈区分配很大的内存,ulimit -a可以看到系统设置栈的上限是8M,越界了,导致段错误int a[1000000]={0};
*/int *p=(int *)malloc(10000000000000*sizeof(int));if(p==NULL)
{
printf("分配失败\n");
}
return 0;
}

内存操作函数 memset()使用

#include <stdio.h>
#include <string.h>
int main()
{int b[10]={0};/*处理一些代码,把b内部的元素改了*//*b[10]={0};  err */int i=0;int n=sizeof(b)/sizeof(b[0]);for(i=0;i<n;i++){b[i]=0;
}memset(b,0,sizeof(b));char str[10];memset(str,'a',sizeof(str));for(i=0;i<10;i++){printf("%c, ",str[i]);
}
printf("\n");
return 0;}
int main01()
{int a;memset(&a,0,sizeof(a));printf("a=%d\n",a);/*中间参数虽然是整形,但是以字符处理*/memset(&a,97,sizeof(a));printf("a1=%c\n",a);int b[10];memset(b,0,sizeof(b));memset(b,0,10 * sizeof(int));return 0;
}

memcpy

#include <stdio.h>
#include <string.h>
int main()
{char p[]="hello\0mike"; /*以字符串初始化,自动在默认隐藏一个结束符'\0';*/char buf[100]; printf("sizeof(p)=%lu\n",sizeof(p));strncpy(buf,p,sizeof(p));printf("buf1=%s\n",buf);printf("buf2=%s\n",buf+strlen("hello")+1);memset(buf,0,sizeof(buf));memcpy(buf,p,sizeof(p));printf("buf3=%s\n",buf);printf("buf4=%s\n",buf+strlen("hello")+1);return 0;
}

内存重叠

![Alt text](./Image [20].png)

#include <stdio.h>
#include <string.h>
int main()
{int a[10]={1,2,3,4,5,6,7,8,9,10};int b[10];/*第三个参数是指拷贝内存的总大小*/memcpy(b,a,10 * sizeof(int));memcpy(b,a,sizeof(a));/*使用memcpy()最好别出现内存重叠*/
/*如果出现内存重叠,最好使用memmove*//*memcpy(&a[2],a,sizeof(int));   err*/memmove(&a[2],a,5*sizeof(int));
}

比较memcmp

#include <stdio.h>
#include <string.h>
int main()
{int a[10]={1,2,3,4,5,6,7,8,9,10};int b[10]={10,2,3,4,5,6,7,8,9,0};if(flag < 0)
{printf("a<b\n");
}else if(flag>0){printf("a>b\n");
}
else
{printf("a==b\n");
}
}
```## 标题你好! 这是你第一次使用 **Markdown编辑器** 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。## 新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:1. **全新的界面设计** ,将会带来全新的写作体验;2. 在创作中心设置你喜爱的代码高亮样式,Markdown **将代码片显示选择的高亮样式** 进行展示;3. 增加了 **图片拖拽** 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;4. 全新的 **KaTeX数学公式** 语法;5. 增加了支持**甘特图的mermaid语法[^1]** 功能;6. 增加了 **多屏幕编辑** Markdown文章功能;7. 增加了 **焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置** 等功能,功能按钮位于编辑区域与预览区域中间;8. 增加了 **检查列表** 功能。[^1]: [mermaid语法说明](https://mermaidjs.github.io/)## 功能快捷键撤销:<kbd>Ctrl/Command</kbd> + <kbd>Z</kbd>
重做:<kbd>Ctrl/Command</kbd> + <kbd>Y</kbd>
加粗:<kbd>Ctrl/Command</kbd> + <kbd>B</kbd>
斜体:<kbd>Ctrl/Command</kbd> + <kbd>I</kbd>
标题:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>H</kbd>
无序列表:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>U</kbd>
有序列表:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>O</kbd>
检查列表:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>C</kbd>
插入代码:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>K</kbd>
插入链接:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>L</kbd>
插入图片:<kbd>Ctrl/Command</kbd> + <kbd>Shift</kbd> + <kbd>G</kbd>## 合理的创建标题,有助于目录的生成直接输入1<kbd>#</kbd>,并按下<kbd>space</kbd>后,将生成1级标题。
输入2<kbd>#</kbd>,并按下<kbd>space</kbd>后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用`TOC`语法后生成一个完美的目录。## 如何改变文本的样式*强调文本* _强调文本_**加粗文本** __加粗文本__==标记文本==~~删除文本~~> 引用文本H~2~O is是液体。2^10^ 运算结果是 1024.## 插入链接与图片链接: [link](https://mp.csdn.net).图片: ![Alt](https://avatar.csdn.net/7/7/B/1_ralf_hx163com.jpg)带尺寸的图片: ![Alt](https://avatar.csdn.net/7/7/B/1_ralf_hx163com.jpg =30x30)居中的图片: ![Alt](https://avatar.csdn.net/7/7/B/1_ralf_hx163com.jpg#pic_center)居中并且带尺寸的图片: ![Alt](https://avatar.csdn.net/7/7/B/1_ralf_hx163com.jpg#pic_center =30x30)当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。## 如何插入一段漂亮的代码片去[博客设置](https://mp.csdn.net/configure)页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 `代码片`.
```javascript
// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。1

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t &ThinSpace; . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. 注脚的解释 ↩︎


http://chatgpt.dhexx.cn/article/H5cMNxfb.shtml

相关文章

Android数字签名机制和应用场景

目录 1 数字签名介绍 1.1 背景 1.2 机制 1.3 使用 1.3.1 ssh-keygen 1.3.2 keytool 2 Android使用数字签名的场景 2.1 未签名的APK VS 签名后的APK 2.2 应用层面&#xff1a;Android对APK的签名要求 2.2.1 Android拒绝安装没有签名的APK 2.2.2 Android不校验证书的合…

学习自旋电子学的笔记01:微磁模拟软件OOMMF的教程(中文版)7-7.3.4章

士不可以不弘毅&#xff0c;任重而道远。——曾子《论语泰伯章》 # 前言 这是oommf软件教程《OOMMF User’s Guide》的中文翻译文章&#xff0c;由于本人水平有限&#xff0c;有些翻译可能有错误&#xff0c;望见谅。 第7章是本手册最重要的章节&#xff0c;由于本人水平是在…

学习自旋电子学的笔记01:微磁模拟软件OOMMF的教程(中文版)17-17.3章

精感石没羽&#xff0c;岂云惮险艰。——李白《豫章行》​​​​​​​ # 前言 这是oommf软件教程《OOMMF User’s Guide》的中文翻译文章&#xff0c;由于本人水平有限&#xff0c;有些翻译可能有错误&#xff0c;望见谅。 目录 17 微磁问题文件格式&#xff08;MIF&#…

2008下半年,来自百度的博客-003

<script type=text/javascript> /**/ </script> /**//**/#nav_extra .body {top:19px;} <script type=text/javascript> /**/ </script> 我的空间 写新文章 上传新照片 选择模板 选择主页类型 #hi{ position:relative; zoom:1;}#hiMsg{display:none;…

Python基础语法详解

目录 一、走进Python 1.软件开发常识 1.1什么是软件 1.2什么是开发 1.3DOS命令行 1.4计算机编程语言介绍 2.Python的概述 2.1Python语言 2.2Python发展史 2.3Python的优缺点 2.4Python的应用 3.数据的存储 3.1内存 3.2进制 4.Python的编码规范 5.注释 6.输入与输…

曼昆 宏观经济学 笔记

曼昆宏观经济学目录 第一章 导言1.1 宏观经济学家研究什么1.2 宏观经济学家是如何思考的内生变量与外生变量假设多个模型的使用价格 黏性与弹性 长期与短期微观模型与宏观模型 一个小故事 第二章 宏观经济学的数据&#xff08;以后再看&#xff09;2.1 国内生产总值投资政府购买…

OpenEuler

目录 实验一&#xff1a;操作系统简介 实验二&#xff1a;内存管理 实验三&#xff1a;进程管理 实验四&#xff1a;中断和异常管理 实验五&#xff1a;内核时间管理 实验六&#xff1a;设备管理 实验七&#xff1a;文件系统 实验八&#xff1a;网络管理 实验九&#x…

h默认试图的方式_试图破坏您的管理模式

h默认试图的方式 © magne.io ©magne.io Heuristics define approaches to problem-solving, system mental representation and in a broader way, a way of thinking. Heuristics we handle daily largely impact the way we think. 启发式方法定义了解决问题的方法…

设备安全——入侵检测IDS

目录 1. 什么是IDS&#xff1f;2. IDS和防火墙有什么不同&#xff1f;2.1 检测与监测2.2 设备所处点不同2.3 作用点不同2.4 动作不同 3. IDS工作原理&#xff1f;3.1、IDS分为实时入侵检测和事后入侵检测&#xff1a;3.2、入侵检测分类&#xff1a;3.3、入侵检测技术途径&#…

Snort入侵检测系统实验

实验内容 搭建网络防御环境学习使用检测工具Snort对网络进行攻击&#xff0c;查看和分析网络防御工具报告对实验结果进行分析整理&#xff0c;形成结论 三、实验步骤 安装入侵检测系统Snort 安装daq依赖程序&#xff0c;输入如下命令&#xff1a; sudo apt-get install fle…

入侵检测系统-3

一、什么是入侵检测 入侵检测(Intrusion Detection )是对入侵行为的检测。它通过收集和分析计算机网络或计算机系统中若于关键点的信息&#xff0c;检查网络或系统中是否存在违反安全策略的行为和被攻击的迹象。入侵检测作为一种积极主动的安全防护技术&#xff0c;提供了对内…

网络安全之入侵检测

目录 网络安全之入侵检测 入侵检测经典理论 经典检测模型 入侵检测作用与原理 意义 异常检测模型&#xff08;Anomaly Detection&#xff09; 误用检测模型&#xff08;Misuse Detection&#xff09; 经典特征案例 ​编辑自定义签名 ​编辑 签名检查过程 检测生命周期…

入侵检测

入侵检测 对于通过网络连接的系统来说&#xff0c;一个重要的安全问题是由用户或软件引起的恶意或者至少是不期望发生的非法入侵。用户非法入侵可能采用的方式是在未经授权的情况下登录到计算机&#xff0c;也可能是已授权用户非法获取更高级别的权限或进行其权限以外的操作。软…

基于机器学习的入侵检测系统

导 语 在过去十年中&#xff0c;机器学习技术取得了快速进步&#xff0c;实现了以前从未想象过的自动化和预测能力。随着这一技术的发展促使研究人员和工程师为这些美妙的技术构思新的应用。不久&#xff0c;机器学习技术被用于加强网络安全系统。 网络安全性最常见的风险就是入…

入侵检测系统(IDS)分类

入侵可以定义为任何类型的对信息系统造成损害的未经授权的活动。这意味着任何可能对信息机密性、完整性或可用性构成威胁的攻击都将被视为入侵。例如&#xff0c;使计算机服务对合法用户无响应的活动被视为入侵。 IDS 是一种软件或硬件系统&#xff0c;用于识别计算机系统上的恶…

IDS(入侵检测系统)

目录 一、结合以下问题对当天内容进行总结 1. 什么是IDS&#xff1f; 2. IDS和防火墙有什么不同&#xff1f; 3. IDS工作原理&#xff1f; 4. IDS的主要检测方法有哪些详细说明&#xff1f; 5. IDS的部署方式有哪些&#xff1f; 6. IDS的签名是什么意思&#xff1f;签名…

入侵检测系统,浅析几个著名的入侵检测系统

原文:http://www.cuntuba520.net/xiaozhishi/2347367.html 一 > 浅析几个著名的入侵检测系统 入侵检测系统是一种对网络传输进行即时监视&#xff0c;在发现可疑传输时发出警报或者采取主动反应措施的网络安全设备。它与其他网络安全设备的不同之处便在于&#xff0c;入侵…

入侵检测系统的原理与应用

入侵检测是一种主动保护自己免受攻击的网络安全技术。作为防火墙的合理补充&#xff0c;入侵检测技术能够帮助系统对付网络攻击&#xff0c;扩展了系统管理员的安全能力&#xff08;包括安全审计、监视、攻击识别和响应&#xff09;&#xff0c;提高了信息安全基础结构的完整性…

IDS入侵检测系统

文章目录 一、IDS是什么二、入侵检测系统的作用和必然性三、入侵检测系统功能四、入侵检测系统的分类五、入侵检测系统的架构六、入侵检测工作过程七、入侵检测性能关键参数八、入侵检测技术九、入侵响应技术十、IDS的部署十一、入侵检测体系结构&#xff08;主机入侵检测、网络…

入侵检测系统详解(IDS)

目录 入侵检测系统&#xff08;IDS&#xff09;概念入侵检测系统的分类根据数据源分类1 基于主机的入侵检测系统&#xff08;HIDS&#xff09;2 基于网络的入侵检测系统&#xff08;NIDS&#xff09; 根据检测原理分类1 异常入侵检测。2 误用入侵检测。 根据体系结构分类1.集中…