C语言基础大全(基于千锋教育超详细教程)

C语言基础

1.第一个c语言程序

#include <stdio.h>
int main()
{
    printf("hello world");
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MDqWMCae-1649660664412)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330114102371.png)]

2.c语言类型以及语句

2.1.关键字

2.1.1数据类型相关关键字

%c ascll码

%d 输出本身

用于定于变量或者类型

类型 变量名 :

char 、short 、 int 、 long 、 float 、 double 、 struct 、 union 、 enum 、 signed 、 unsigned 、 void

1.char 字符型 用char定义的变量 是字符型变量 占一个字节

char ah = 'a'	=为赋值号

char ah = 'abc'  //错误写法

printf("c =%c\n", c);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LfWJfWBD-1649660664413)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330131522920.png)]

看一些各类型占用几个字节

#include <stdio.h>
int main()
{

    char a;
    short int b;
    int c;
    long int d;
    float e = 3.8f;
    double f = 3.8;
    printf("sizeof(a) =%d\n", sizeof(a)); // 1
    printf("sizeof(b) =%d\n", sizeof(b)); // 2
    printf("sizeof(c) =%d\n", sizeof(c)); // 4
    printf("sizeof(d) =%d\n", sizeof(d)); // 4
    printf("sizeof(e) =%d\n", sizeof(e)); // 4
    printf("sizeof(f) =%d\n", sizeof(f)); // 8

    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bixRcS61-1649660664414)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330133001182.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oLL9YkqE-1649660664415)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330133737667.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-04NTFaz6-1649660664415)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330133914065.png)]

12.void关键字 空类型的关键字

char 、 int 、 float 、都可以定义变量

void 不能定义变量 ,没有void 类型的返回值

void是用来修饰函数的参数或者返回值,代表函数没有参数或者没有返回值

例子:

​ void fun(void){

​ }

代表fun没有返回值 fun函数没有参数

2.1.2储存类型相关关键字

register 、 static(静态) 、 const(常量) 、 auto 、 extern

1.register

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iY3dHlyG-1649660664416)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330134404256.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yayBSzuM-1649660664416)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330135001474.png)]

不能修饰数组 只能修饰 字符型 整形 ,不能修饰浮点型

2.static

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T5rRwBOg-1649660664416)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330135124942.png)]

3.const

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bedznn1N-1649660664417)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330135141163.png)]

4.auto

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m7V1iOsa-1649660664417)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330135155773.png)]

5.extern

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7QCrDoNY-1649660664418)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330135211706.png)]

2.1.3 控制语句相关的关键字

if 、 else 、 break 、 continue 、 for 、 while 、 do 、 switch 、 case 、goto 、default

2.1.4 其他关键字

sizeof 、 typedef 、 volatile

1.sizeof 测量字节数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jU53nDHn-1649660664418)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330135815570.png)]

2.typedef 重命名相关的关键字

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JaIdvkZF-1649660664419)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330135948633.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pB7iKiMD-1649660664420)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330140052763.png)]

#include <stdio.h>
// 1.short int a ;
// 2.short int INT16;
// 3.typedef short int INT16;
typedef short int INT16;
int main()
{
    short int b = 101;
    INT16 c = 111;
    printf("b=%d\n", b);
    printf("c=%d\n", c);
}
3.volatile 易改变得

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CLgvd5t4-1649660664421)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330140725983.png)]

Linux风格

stu_num

驼峰风格

StuNum

大小写敏感

int Num;

int num;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c1wUPTfo-1649660664421)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330141058966.png)]

2.2 数据类型

2.2.1 基本数据类型

char 、 short int 、 int 、 long int 、 float 、 double

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2lFQ4tgs-1649660664422)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330141235803.png)]

字符数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ONn79NK-1649660664422)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330141446722.png)]

整型数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bOykGvgW-1649660664422)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330151540535.png)]

十进制:以正常数字 1-9 开头 如457 789

八进制 :以数字0开头 如 0123

十六进制:以0x开头 如0x123

实型数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yixNa7fZ-1649660664423)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330152439833.png)]

格式化输出字符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FlTZ1xIG-1649660664423)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330152610482.png)]

十进制转二进制
将余数和最后的1从下向上倒序写 就是结果
例如302
302 2 = 151 余0
151 2 = 75 余1
75 2 = 37 余1
37 2 = 18 余1
18 2 = 9 余0
9 2 = 4 余1
4 2 = 2 余0
2 2 = 1 余0
1 2=0 余1
故二进制为100101110
再联想到二进制转十进制
二进制转为十进制的时候,先把二进制从高位(最左边的“1”)开始按从上到下的顺序写出 ,第一位就是最后的商 “2 2 = 1 余0 “,余数肯定是加零。其他位数如果有”1“(原来的余数),就先乘以”2“再加”1“。
下面就是从第一位开始乘以2加余数的方法算回去
例如 100101110
1…………0 2+1=1…………余数为1
0…………1 2+0=2………… 余数为0
0 …………2 2+0=4 ………… 余数为0
1 …………4x2+1=9……………… 余数为1
0…………9x2+0=18 ……………… 余数为0
1 …………18 2+1=37 …………余数为1
1…………… 37 2+1=75…………余数为1
1………………75 2+1=151………… 余数为1
0………………151 2+0=302 ………… 余0
所以得到十进制数302
另:1*2^8+0*2^7+0*2^6+1*2^5+0*2^4+1*2^3+1*2^2+1*2^1+0*2^0=302


八进制转十进制:整体顺序、小数点不变,个位乘8的0次方+十位乘8的1次方...=十进制得数,即可。小数部分从左到右乘8的负一次方开始,以此类推。
十进制转八进制:整体顺序、小数点不变,整数部分除8,余数倒着从左向右排,小数部分乘8,整数自左向右排。
2.2.2 构造类型

概念:由若干个相同或者不同类型的数据构成的集合,这种数据类型被称为构造类型

例:int a[10];

**数组 、 结构体 、共用体 、 枚举 **

2.2.3 类型转换
自动转换

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ma0vnDsm-1649660664424)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330160210868.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ma66v1H9-1649660664424)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330161255695.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QSQWnlIU-1649660664426)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330161331099.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ADckVJb-1649660664426)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330163124854.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pV1ZBXXK-1649660664426)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330170226354.png)]

#include <stdio.h>
int main()
{
    // printf("%1f\n", 5.0 / 2);
    // return 0;

    int a = -8;
    unsigned int b = 7;
    if (a + b > 0)
    {
        printf("a+b >0\n");
    }
    else if (a + b < 0)
    {
        printf("a+b <0\n");
    }
    else
    {
        printf("a+b =0\n");
    }
    printf("a+b =%x\n", a + b);
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ot2Hsb21-1649660664427)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330170836685.png)]

  int a;
    float f = 5.8f;
    a = f;
    printf("a=%d", a);  //5
    return 0;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z8xqQU6z-1649660664427)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330171126176.png)]

强制转换

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SeoN6a4J-1649660664428)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330171240716.png)]

 float x = 0;
    int i = 0;

    x = 3.6f;
    i = (int)x;
    printf("i=%d\n", i);

    printf("x=%1f\n", x);
    return 0;

说明:

​ 无论是强制类型转换或者是自动转换,都只是为了本次运算的需要,而对变量的数据长度进行临时性的转换,而不改变数据定义的类型以及它的值。

2.2.4 指针

2.3运算符

2.3.1 运算符

用算术运算符将运算对象(也称为操作数)连接起来的、符合C语法规则的式子,称为C算术表达式

运算对象包括常量,变量,函数等等…

​ 例如:a*b/c - 1.5 + ‘a’

2.3.2 运算符的分类

1、双目运算符:即参加运算的操作数有两个

​ 例 +

​ a+b

2.单目运算符:参加运算的操作数只有一个

++自增运算符 给变量值 +1

– 自减运算符

int a =10;

3.三目运算符: 即参加运算的操作数有三个

()?()😦)

2.3.3 算术运算符

/ + - % += -= *= /= %=

10%3 表达式的结果为 1

复合运算符:

​ a+=3 相当于 a= a+3

​ a*=6+8 相当于 a = a*(6+8)

2.3.4 关系运算符

(> 、 < 、== 、>= 、!=)

一般用于判断条件是否满足或者循环语句

2.3.5 逻辑运算符

1.&& 逻辑与

​ 两个条件都为真 。 则结果为真

​ if()(a>b)&&(a<c))

if(b<a<c)//这种表达式是错误的

2.|| 逻辑或

​ 两个条件至少有一个为真,则结果为真

​ if()(a>b) || (a<c))

3.! 逻辑非

​ if(!(a>b))

{

}

2.3.6 位运算符

16进制 除16得余

10进制 除10得余

-数的原码等于正数的原码加个符号位1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6IXIadxW-1649660664430)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330215822663.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KAh6ckPT-1649660664430)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330222009122.png)]

同一为一 ,有0为0.

按位与

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kZ4jHvEJ-1649660664431)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331101220336.png)]

两个都是0则结果为0.有一位为1 则结果为1.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cTBz1sIk-1649660664431)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331103149272.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fOiJzeEw-1649660664432)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331111304992.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V9JEDUXj-1649660664433)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331111334239.png)]

对于无符号数来说,补的就是0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OYluGwdY-1649660664434)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331111533674.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1pPVF56W-1649660664434)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331112145450.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZgfRRKNa-1649660664435)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220330220106137.png)]

2.3.7 条件运算符号

三目运算符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L4qTsmf6-1649660664436)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331113128233.png)]

2.3.8 逗号运算符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QM7CeaXp-1649660664436)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331113444463.png)]

2.3.9 自增自减运算符

​ i++ i–

运算符在变量的后面,在当前表达式中先用i的值,下条语句的时候i 的值改变

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JInPg1r2-1649660664437)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331130542718.png)]

++i --i

在当前表达式中先用i自增后的值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-67IeoJOz-1649660664437)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331130440749.png)]

2.3.10 运算符优先级及结合性

运算符优先级

​ 在表达式中按照优先级先后进行运算,优先级高的优于优先级低的先运算。

​ 优先级一样的按结合性来运算

int a;

a =2+5+3*4-6

运算符结合性

左结合性:从左往右计算

int a;

a=2+3.+9+10;

右结合性:从左往右运算

int a,b,c,d;

a=b=c=d=100;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GOQt5bl7-1649660664438)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331131245656.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DPM0ZHbD-1649660664438)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331131430949.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1kaRIZLw-1649660664439)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331131513416.png)]

2.4 控制语句相关关键字讲解

2.4.1 控制语句相关的关键字
1、if语句

形式 :

if( 条件表达式)
{ //复合语句 ,若干条语句的集合
	语句一:
	语句二;
	
	}

如果条件成立执行大括号里面的所有语句,不成立的话大括号里的语句不执行

2、

if(条件表达式)

 	{

}else{

}

if else 语句的作用是,如果if条件成立,执行if后面{}内的语句,否则执行 else 后的语句.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZcCmH3zM-1649660664439)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331132649328.png)]

2.switch 语句
switch (表达式) //表达式只能是字符型或者整型的(short int   int  long int)

{
	case 常量表达式1:
		语句1;
		break;
	case 常量表达式2:
		语句2;
		break;
	default: 语句3; break;
}
注意:break 的使用
2.4.2 循环控制语句
1、for()循环

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iLpR9fKV-1649660664440)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331151831680.png)]

 // for (int i = 0; i < 5; i++)
    // {
    //     if (i == 3)
    //     {
    //         printf("这个世界很奇妙\n");
    //         continue;
    //     };
    //     printf("i =%d\n", i);
    // };
    // return 0;
    int sum = 0;
    for (int i = 0; i <= 100; i++)
    {
        sum += i;
    };
    printf("1-100的和sum = %d", sum);
    return 0;

循环嵌套

//99乘法表
//循环嵌套
    int i, j;
    int sum = 0;
    for (i = 1; i <= 9; i++) //外层循环一次,内层循环一轮
    {
        for (j = 1; j <= i; j++)
        {

            printf("%d*%d=%d ", j, i, j * i);
        };
        printf("\n");
    };
2、while 循环

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HjO4MICU-1649660664440)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331161036106.png)]

//1-100的和
int i = 1;
    int sum = 0;
    while (i <= 100)
    {
        sum += i;
        i++;
    }
    printf("sum=%d\n", sum);
    return 0;

do{} while(); //至少执行一次

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UGlqdyxq-1649660664441)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331161408879.png)]

int i = 1;
    int sum = 0;
    do
    {
        sum += i;
        i++;
    } while (i <= 100);
    printf("sum=%d\n", sum);
    return 0;

对于循环来说

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DN4iJgQJ-1649660664441)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331161826494.png)]

3、goto

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BEBYaXx1-1649660664442)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331162134158.png)]

程序经量少使用goto

4.水仙花数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EiT83G1e-1649660664442)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331162241934.png)]

#include <stdio.h>
int main()
{
    int a, b, c;
    int i;
    for (i = 0; i <= 999; i++)
    {
        a = i / 100;      //百位
        b = i % 100 / 10; //十位
        c = i % 10;       //各位

        if (i == a * a * a + b * b * b + c * c * c)
        {

            printf("水仙花数为=%d", i);
        };
    };

    return 0;
}
#include <stdio.h>
int main()
{
    /*
    任意给出一个年月日、判断是一年的第几天
    闰年算法:能被4整除且不能被100整除,或者 能被400整除
    如:2012 5 10 是这一年的第131天
    提示switch
    */
    int year, month, day;
    int sum;
    printf("please input year month day:\n");
    scanf_s(" %d %d %d", &year, &month, &day);
    switch (month)
    {
    case 1:
        sum = day;
        break;
    case 2:
        sum = 31 + day;
        break;
    case 3:
        sum = 31 + 28 + day;
        break;
    case 4:
        sum = 31 + 28 + 31 + day;
        break;
    case 5:
        sum = 31 + 28 + 31 + 30 + day;
        break;
    case 6:
        sum = 31 + 28 + 31 + 30 + 31 + day;
        break;
    case 7:
        sum = 31 + 28 + 31 + 30 + 31 + 30 + day;
        break;
    case 8:
        sum = 31 + 28 + 31 + 30 + 31 + 30 + 31 + day;
        break;
    case 9:
        sum = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + day;
        break;
    case 10:
        sum = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + day;
        break;
    case 11:
        sum = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + day;
        break;
    case 12:
        sum = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + day;
        break;
    default:
        sum = 0;
        printf("你输入月份有误");
        break;
    }
    
    if (month > 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
    {
        sum += 1;
    }
    printf("%d %d %d 是一年中的第%d 天\n", year, month, day, sum);
    return 0;
}

3.数组

3.1数组的概念

数组是若干个相同类型的变量在内存中有序存储的集合

int a[10]; //定义了一个整型的数组 a, a是数组的名字,数组中有10个元素,每个元素的类型都是 int 类型,而且在内存中连续存储。

这十个元素分别是a[0] a[1] … a[9]

a[0]~a[9]在内存中连续的顺序存储

3.2数组的分类

3.1.1按照元素的类型分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m3aZo3sV-1649660664443)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331172910862.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BfdrmL5Q-1649660664444)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331173159764.png)]

3.2.2 按维数分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ccDgTN3Y-1649660664444)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331173359170.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TeXmYZtY-1649660664445)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331173419099.png)]3.3数组的定义

定义一个数组,在内存里分配空间

3.3.1 一维数组的定义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TIOVYigU-1649660664445)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331174540507.png)]

3.3.2 二维数组的定义

格式:

​ 数据类型 数组名 [行的个数] [列的个数];

​ int a [4] [5];

​ 定义了20个int 类型的变量 分别是

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aiCUi4W7-1649660664446)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220331180506119.png)]

因为一个整数占4个字节 可以按照这样计算

二维数组可以不指定行数,但是必须指定列数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7lpGEwRB-1649660664447)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220401093931210.png)]

3.4数组的初始化

定义数组的时候,顺便给数组的元素赋初值,及开辟的内存空间同时并且给元素赋值。

3.4.1一维数组的初始化

a 、 全部初始化

int a[5] = {2,4,7,8,5};

b 、 部分初始化

​ int a[5] = {2,4,3};初始化赋值不够后面补0

​ a[0] = 2 a[1] = 4 a[2] =3 a[4] =0 a[5] =0

注意:只能省略后面的元素,可以不初始化,不能中间的不初始化。

3.4.2 二维数组的定义并初始化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nYybKbXP-1649660664447)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220401094452739.png)]

#include <stdio.h>
int main()
{
    int a[2][2] = {{1, 2}, {4, 5}};
    int b[3][3] = {
        {1, 2},
        {9, 8}};
    int i, j;
    for (i = 0; i < 2; i++)
    {
        for (j = 0; j < 2; j++)
        {
            printf("a[%d][%d]=%d ", i, j, a[i][j]);
        };
    };
    for (i = 0; i < 3; i++)
    {
        for (j = 0; j < 3; j++)
        {
            printf("a[%d][%d]=%d ", i, j, b[i][j]);
        };
        printf("\n");
    };
    return 0;
}
#include <stdio.h>
int main()
{
    int a[2][3] = {2, 2, 4, 4, 5, 6};
    int i, j;
    for (i = 0; i < 2; i++)
    {
        for (j = 0; j < 3; j++)
        {
            printf("a[%d][%d]=%d", i, j, a[i][j]);
        };
        printf("\n");
    };
}

3.5数组元素的引用方法

3.5.1 一维数组元素的引用方法

数组名[下标]; //下标代表数组元素在数组中的位置

int a[5];

3.5.2 二维数组元素的引用方法

数组名[行下标] [列下标]

int a [4] [5]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y8vKuj7W-1649660664448)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220401100950995.png)]

3.5.3 字符数组

char c1[] = {‘c’,‘a’,‘g’,‘r’};

char c2[] = “c prog”;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-et9IrVqY-1649660664448)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220401102245644.png)]

[数组是若干个相同类型变量的集合][]

两道练手题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HV98oiTq-1649660664448)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220401112245495.png)]

#include <stdio.h>
int main()
{
    int i;
    int sum = 0;
    int year, month, day;
    int buf[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    printf("please input year month day\n");
    scanf_s("%d %d %d", &year, &month, &day);
    if (day >= 30 || day < 1)
    {
        printf("你输入的信息有误");
    }
    else
    {

        for (i = 0; i < month - 1; i++)
        {
            sum += buf[i];
        }
        sum += day;
        if (month > 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
        {
            sum += 1;
        }
        printf("sum=%d\n", sum);
    }
    return 0;
}

打字游戏

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4nmB995c-1649660664449)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220401131148819.png)]

#include <stdio.h>
#include <conio.h>
#include <time.h>
void help(void)
{

    printf("\n******************************************");
    printf("\n* 输入过程中无法退出!                     *");
    printf("\n* 请按住所给字母敲击键盘!                 *");
    printf("\n* 请按任意键开始测试,按下首字母时候开始计时!");
    printf("\n* 输入错误则以_表示                        ");
    printf("\n******************************************\n\n");
}
int main()
{
    char ch;
    char str[51] = "";
    int i;

    int count;

    time_t start_time, end_time; // typedef long long time_t
    while (1)
    {
        system("cls"); //清除屏幕
        help();
        ch = _getch();
        srand(time(NULL));
        for (i = 0; i < 50; i++)
        {
            str[i] = rand() % 26 + 'a'; // rand()产生一个随机数,26个字母 对26取余  是一个0-25的随机数
        }
        str[50] = "\0";

        printf("%s\n", str);
        count = 0;
        for (i = 0; i < 50; i++)
        {
            ch = _getch();
            if (i == 0)
            {
                start_time = time(NULL);
            }
            if (ch == str[i])
            {
                count++;
                printf("%c", ch);
            }
            else
            {

                printf("_");
            }
        }
        end_time = time(NULL);
        printf("\n正确率: %d%%\n", count * 100 / 50);
        printf("用时%d秒", (long int)end_time - start_time);
        //当我输入空格重新开始,输入其他无效,输入esc退出
        while (1)
        {
            ch = _getch();
            if (ch == ' ')
            {
                break;
            }
            if (ch == 27)
            {
                return 0;
            }
        }
    }

    return 0;
}

4.函数

4.1函数的概念

函数是c语言的功能单位,实现一个功能可以封装一个函数来实现。

定义函数的时候一切以功能为目的,根据功能去定函数的参数和返回值。

4.2函数的分类

1、从定义的角度分类(即函数是谁实现的)

  1. 库函数(c库实现的)
  2. 自定义函数(程序员自己实现的函数)
  3. 系统调用

2、从参数角度分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7QzEGTfq-1649660664449)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220401141601267.png)]

3 、从返回值的角度分类

1.带返回值的函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GGJc1oAs-1649660664450)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220401142237504.png)]

2.没有返回值的函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PmDH8tQN-1649660664450)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220401144514427.png)]

4.3函数的定义

什么叫做函数的定义呢?即函数的实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-61NS3hK7-1649660664450)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220402095635167.png)]

不能再函数体内定义另一个函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eOw6p5hx-1649660664451)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220402095940734.png)]

4.4函数的声明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4kz3tgEL-1649660664451)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220402101003626.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B52kLNzI-1649660664452)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220402101442600.png)]

声明就是在一个函数中调用另一个函数

1.直接声明法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nVxLDqOF-1649660664452)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220402101510543.png)]

#include<stdio.h> //这种类型是C库文件的声明

#include “4_3.h” //是对程序员创建的程序的声明

2.间接声明法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t6jGkYGQ-1649660664452)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220402101907638.png)]

3.分文件声明法

将函数都写在一个.c中,使用头文件.h来进行声明,然后再其他文件中就可以直接使用了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T7ZFG7pX-1649660664453)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220402103034664.png)]

4.5 函数的调用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N4Fpe71r-1649660664453)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220402103315924.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JVIwclJ4-1649660664454)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220402103508303.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RtmHhF67-1649660664454)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220402103410739.png)]

4.6函数的总结

在定义函数的时候 ,关于函数的参数和返回值是什么情况,完全取决于函数的功能。

使用函数的好处?

1、定义一次,可以多次调用,减少代码的冗余度。

2、使咱们的代码,模块化更好,方便程序调试,而且阅读方便。

递归函数

#include<stdio.h>
int fun(int x){
    int p;
    if(x==0||x==1)p=3;
    else p=x-fun(x-2);
    return p;
}
int main(int argc, char const *argv[])
{
    printf("%d\n",fun(12));
    return 0;
}
//fun(7)=7-fun(5)=7-(5-fun(3))=7-(5-(3-fun(1)))=7-(5-(3-3))=7-5=2 ”

4.7 变量的存储类别

4.7.1 内存的分区:

1、内存:物理内存、虚拟内存

​ 物理内存:实实在在存在的存储设备

​ 虚拟内存:操作系统虚拟出来的内存

​ 操作系统会在物理内存和虚拟内存之间做映射。

在32位平台下,每个进程的寻址范围是4G,0x00 00 00 00 -0xff ff ff ff

在写应用程序,咱们看到的都是虚拟地址。

2、在运行程序的时候,操作系统会将  虚拟内存进行分区。

  1. 在动态申请内存的时候,在堆中开辟内存。

  2. 主要存放局部变量。

  3. 静态全局区

    1. 未初始化的静态全局区

      静态变量(定义变量的时候,前面加static修饰),或全局变量,没有初始化的,存在此区

    2. 初始化的静态全局区

      全局变量、静态变量、赋过初值的,存放此区

  4. 代码区

    存放咱们的代码。

  5. 文字常量区

    存放常量的。

4.7.2 普通的全局变量

概念:

​ 在函数外部定义的变量

	int num =100; //num 就是一个全局变量
	int main(){
	
		return 0;
	}

作用范围:

全局变量的作用范围,是程序所有地方。

​ 只不过用之前需要声明。声明方法 extern int num;

​ 注意声明的时候,不要赋值。

生命周期:

​ 程序运行的整个过程,一直存在,直到程序结束。

注意:定义普通的全局变量的时候,如果不赋初值,它的默认值为0

4.7.3 静态的全局变量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6E6fWh55-1649660664454)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220403164550691.png)]

#include<stdio.h>
void fun(void) {
	static int num = 3; //这就是静态局部变量的好处 ,只执行一次,下次不参与赋值了,此处
	//	如果不用static修饰,则在下次执行这个方法的是和num 还是会被赋值。
	//不用静态修饰的在内存空间的分配中是同一个
	int num1 = 4;
	num++;
	num1++;
	printf("num = %d\n", num);
	printf("num1 = %d\n", num1);
}

int main() {
	fun();
	fun();
	fun();
	return 0;
}
4.7.4 普通的局部变量

概念:

​ 在函数内部定义的,或者复合语句中定义的变量

int main(){
    int num; //局部变量
    {
        int a;//局部变量
    }
}

作用范围:

​ 在函数中定义的变量,在函数中有效。

​ 再复合语句中定义的,再复合语句中有效。

生命周期:

​ 在函数调用之前,局部变量不占用内存空间,调用函数的时候,才为局部变量开辟空间,函数结束了,局部变量就释放了。

在复合语句中的定义亦如此。

#include<stdio.h>
void fun(void) {
	int num = 3;
	num++;
	printf("num = %d", num);
}
void fun2( int x) {//无论在函数内部还是形参,定义的都是普通的局部变量。
	x++;
	printf("x=%d\n", x);
}
int main() {
  
	fun();//每次调用方法,都会重新开辟内存空间,下一次调用也会重新开辟。
	fun();
	fun();
	fun2(3); //调用这个方法,会开辟内存空间,然后打出四。
	
	return 0;
}

4.7.5 静态的局部变量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QLoPeBjS-1649660664455)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220403170643017.png)]

#include<stdio.h>
void fun() {
	static int num = 3;
	num++;
	printf("num = %d \n", num);
}
int main() {
	fun();
	fun();
	fun();
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0tQ9ezq0-1649660664455)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220403170831889.png)]

void fun2(void) {
	//int a;
	static int b;
	//printf("普通局部变量 = %d \n", a); //在linux 中有效是随机的
	printf("静态局部变量 = %d \n", b);//是0
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MHJOj8pA-1649660664455)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220403171448675.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Rjajb1F-1649660664456)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220403171819955.png)]

4.7.6 外部函数

​ 咱们定义的普通函数,都是外部函数。

​ 咱函数可以在程序的任何一个文件中调用

4.7.7 内部函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H1Hrs820-1649660664456)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220403172617175.png)]5.预处理 、 动态库 、 静态库

5.1 c语言编译过程

1:预编译

​ 将.c 中的文件展开、宏展开

​ 生成的文件是.i 文件

2:编译

​ 将预处理之后的.i 文件生成 .s 汇编文件

3、汇编

​ 将.s 汇编文件生成.o 目标文件

4、链接

​ 将.o 文件链接成目标文件

Linux 下 GCC编译器编译过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NG5z1Wpp-1649660664457)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404014338085.png)]

5.2 include

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wWF5FFYc-1649660664457)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404015646638.png)]

会将头文件在预处理阶段转换成这种语句。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7KYMhqXI-1649660664458)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404020237728.png)]

5.3 define

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-axn0CcHx-1649660664458)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404020409717.png)]

#undef PI // 从此行开始,宏失效

#define PI 3.1415926
int main()
{
    double f;
    printf("PI= %lf\n", PI);
    f = PI;
    #undef PI // 从此行开始,宏失效
    printf("f= %lf\n", f);
    
    #define PI 3.1415926  //重新定义一个宏
    return 0;
}
//也可以将define 放入头文件中 调用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vKhjOhaf-1649660664458)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404021307907.png)]

#define S(a, b) a *b
int main()
{
    int num;
    num = S(7, 8);
    printf("num = %d", num);
    num = S(3 + 5, 7); // 3+5*7 副作用,先算乘法了
    printf("num = %d", num);
    return 0;
}

//我们建议带参数的运算最好加上括号,优先级高,避免出现副作用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eFsxXNy1-1649660664459)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404024334622.png)]

5.4 选择性编译

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9lXxj28A-1649660664459)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404031333665.png)]

#define AAA
int main()
{
#ifdef AAA
    printf("hello world\n");
#else
    printf("hello China!!\n");
#endif
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vSs4lCoJ-1649660664460)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404155737854.png)]

#include "选择性编译.h"
#include "选择性编译.h"
int main() {
	return 0;

}


.h
#ifndef __选择性编译_H__
#define __选择性编译_H__
extern int fun(int x, int y);
#endif
//防止头部重复包含

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LHBpbzon-1649660664460)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404155915743.png)]

记住一下选择性编译都是在预处理环境下进行的

5.5 静态库

一:动态编译

​ 动态编译使用的是动态库文件进行编译

​ gcc hello.c -o hello

​ 默认咱们使用的是动态编译方法

二:静态编译

​ 静态编译使用的静态库文件进行编译

​ gcc -static hello.c -o hello

三:静态编译和动态编译的区别

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-clMYSNMd-1649660664460)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404171319813.png)]

//mylib.c
    
int max(int x,int y) {
	return (x > y) ? x : y;
}
int min(int x, int y) {
	return (x > y) ? x : y;
}


//mylib.h
#ifndef __mylib_h__
#define __mylib_h__

extern int max(int x, int y);
extern int min(int x, int y);
#endif 

//mytest.c 
#include <stdio.h>
#include"mylib.h"
int main(int args,char *argv[]) {

	int a = 10, b = 20, max_num, min_num;
	max_num = max(a, b);
	min_num = min(a, b);
	printf("max_num = %d\n", max_num);
	printf("min_num = %d\n", min_num);
	return 0;

}

把mylib.c制作成静态库文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FWHgbF8f-1649660664461)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404174023073.png)]

以前

​ gcc mytest.c mylib.c mylib.h mylib.o mytest

方法一要求库文件和头文件都在指定路劲下,才会生效。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5x5aZMum-1649660664461)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404180827029.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kYrKVKht-1649660664461)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404181232497.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TcWtQTRD-1649660664462)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404181803267.png)]

5.6 动态库

第一步

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C2zZGELz-1649660664462)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404182700912.png)]

有了动态库开始编译

该步骤需要先指定库文件和头文件的指定路径方便程序查找运行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MPp7tJlE-1649660664462)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404183846414.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b9WjWfLZ-1649660664463)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404183830013.png)]

6.指针

6.1.1 关于内存那点事

存储器:存储数据器

外存

​ 外村又叫做外部存储器,长期存放数据,掉电不丢失数据。

​ 常见的外存设备:硬盘、flash、rom、u盘、光盘、磁带

内存

​ 内存又叫内部存储器,展示存放数据,掉电数据丢失

​ 常见的内存设备:ram 、 DDR

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4QD3GWBi-1649660664463)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404195840339.png)]

32位下 是 4个g

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UEZnPcye-1649660664464)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404200155971.png)]

每一个存储地址是一个字节都代表一个字符

例如’a’ 存放的是ascll码的二进制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O2Hl6yHl-1649660664464)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404200329903.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ClsHs56B-1649660664465)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404200348046.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fo0KXuJk-1649660664465)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404200946920.png)]

内存以字节为单位来存储数据的,咱们可以将程序中的虚拟寻址空间,看成一个很大的一维的字符数组。。。(4g)

6.1.2 指针的概念

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yS1DsqRP-1649660664466)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404211649924.png)]

写了个100 ,就是100的二进制 写了个a ,字符的ascll码的二进制。

指针变量:是个变量,是一个指针变量,即用这个变量来存放一个地址编号

在32位平台下,地址总线是32位的,所以地址是32位编号,所以指针变量是32位的即4个字节。

注意: 1:

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aLxW1jlH-1649660664467)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404223340875.png)]

当然,在64位系统,占用8个字节。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oTbdKcgv-1649660664468)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404223538380.png)]

/*指针变量占用多少字节
 
我们讲过,指针变量根据“基类型”的不同,有 int * 型,float * 型,double * 型,char * 型等。
 
但是我们前面在讲数据类型的时候讲过,int 型变量占用 4 字节,float型变量占用 4 字节,double类
型变量占用 8字节,char类型占用 1 字节。
那么“指针变量”占多少字节呢?是不是基类型占用多少字节,该变量就占用多少字节呢?同样,用
sizeof写一个程序看一下就知道了。*/
 
#include<stdio.h>
int main(void)
{
    int *a = NULL;
    float *b = NULL;
    double *c = NULL;
    char *d = NULL;
    printf("%d %d %d %d\n", sizeof(a), sizeof(b), sizeof(c), sizeof(d));
    return 0;
}
/*运行结果为8  8  8  8
 
可见,不管什么样的基类型,系统指针给指针变量分配的内存空间都是8字节,在C语言中,指针变量的“基类型”仅用来指定该指针变量可以指向的变量类型,并没有其他意思。不管基类型是什么类型的指针变量,他仍然是指针变量,所以仍然占用 8 字节。
 
 
那么为什么系统给指针变量分配的是 8 字节呢?兄弟都9102年了,还在使用32位系统?当然是64位系统啦,64位计算机有64根地址线,每根地址线要么是 0 要么是 1,只有两种状态。内存单元中的每个地址都是由着 64根地址线通过不同的状态组合而成的,而 8 字节刚好 64 位,正好能存储下所有内存单元的地址信息。*/

6.1.3 指针的定义方式

1.简单的指针变量

数据类型 * 指针变量名

​ int * p ; // 定义了一个指针变量 p

在定义指针变量的时候 * 是用来修饰变量的 ,说明变量 p 是一个指针变量

​ 变量名称是p

2.关于指针的运算符

​ & 取地址 、 *取值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wwxYAiMB-1649660664468)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404230413669.png)]

p保存了 a的地址 ,也可以说是p指向了 a

p和a 的关系分析:a的值是0x1234adcd ,假如a 的地址是:0xbf e8 98 68

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m50li5s0-1649660664470)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404231024967.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T0JE4qG2-1649660664470)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404231218022.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5muXD9ia-1649660664471)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404231257965.png)]

#include <stdio.h>
int main()
{
    int a = 100, b = 200;
    int *p_1, *p_2 = &b; //因为*p_1是局部变量,指向哪里不确定,被称为野指针。
    p_1 = &a;
    printf("a=%d\n", a);
    printf("*p_1=%d\n", *p_1);
    printf("b=%d\n", b);
    printf("*p_2=%d\n", *p_2);
    
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wr3huheK-1649660664471)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404232305806.png)]

3.指针大小
/*指针变量占用多少字节
 
我们讲过,指针变量根据“基类型”的不同,有 int * 型,float * 型,double * 型,char * 型等。
 
但是我们前面在讲数据类型的时候讲过,int 型变量占用 4 字节,float型变量占用 4 字节,double类
型变量占用 8字节,char类型占用 1 字节。
那么“指针变量”占多少字节呢?是不是基类型占用多少字节,该变量就占用多少字节呢?同样,用
sizeof写一个程序看一下就知道了。*/
 
#include<stdio.h>
int main(void)
{
    int *a = NULL;
    float *b = NULL;
    double *c = NULL;
    char *d = NULL;
    printf("%d %d %d %d\n", sizeof(a), sizeof(b), sizeof(c), sizeof(d));
    return 0;
}
/*运行结果为8  8  8  8
 
可见,不管什么样的基类型,系统指针给指针变量分配的内存空间都是8字节,在C语言中,指针变量的“基类型”仅用来指定该指针变量可以指向的变量类型,并没有其他意思。不管基类型是什么类型的指针变量,他仍然是指针变量,所以仍然占用 8 字节。
 
 
那么为什么系统给指针变量分配的是 8 字节呢?兄弟都9102年了,还在使用32位系统?当然是64位系统啦,64位计算机有64根地址线,每根地址线要么是 0 要么是 1,只有两种状态。内存单元中的每个地址都是由着 64根地址线通过不同的状态组合而成的,而 8 字节刚好 64 位,正好能存储下所有内存单元的地址信息。
当然在32位平台下,所有指针的地址指向的都是4个字节。
*/

6.1.4 指针的分类

按照指针指向的数据的类型来分

1:字符指针

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nHBzW7oR-1649660664472)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404233319200.png)]

2:短整形指针

​ short int *p; //定义了一个短整型的指针变量p,只能存放短整型变量的地址。

​ short int a;

​ p= &a; //&取变量a的地址

3:整形指针

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CYUzFZsL-1649660664472)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404233510743.png)]

4:长整型指针

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rREI3Tph-1649660664473)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404233652852.png)]

5:float 型指针

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j2icRoIO-1649660664474)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404233737331.png)]

6:double型指针

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c7EI2kGg-1649660664474)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220404233808919.png)]

总结:无论什么类型的指针变量,在32位系统下,都是4个字节。(同理,在64位系统下,都是8位字节)指针只能存放对应类型的变量的地址编号(通用指针任意地址编号)。

6.1.5 指针和变量的关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hOom6Sif-1649660664474)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220405000548584.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dN4yPPlQ-1649660664475)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220405000830103.png)]

#include <stdio.h>
int main()
{
    int *p1, *p2, temp, a, b;
    p1 = &a;
    p2 = &b;
    printf("请输入a和b的值 = \n");
    scanf_s("%d %d", p1, p2);
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
    printf("a =%d,b=%d = \n", a, b);
    printf("*p1=%d *p2=%d \n", *p1, *p2);

    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KTj2KDtD-1649660664475)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220405004257546.png)]

#include <stdio.h>
int main()
{
    int a = 0x12345678, b = 0xabcdef66;
    char *p1, *p2;
    int *p;
    p1 = (char *)&a; //强制转换
    p2 = (char *)&b;
    printf("%0x %0x\n", *p1, *p2); //只打印后面两位也就是最低阶的,一个内存空间的1个字节
    //在定义的时候 * 是修饰这个变量是个指针变量,而在调用时候,是代表取值的意思。。
    //如果去掉* 话 打印的就是指向对象的地址而不是内存空间分配的值
    p = &a;
    printf("*p =%0x\n", *p); //都是整型打印的是4个字节
    
    p1++;
    p2++;
    printf("%0x %0x\n", *p1, 0xff & (*p2));
    return 0;
}
78 66
*p =12345678
56 ef

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e6zzmTuh-1649660664476)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220405005805252.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hweBVyAL-1649660664476)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220405010600617.png)]

6.1.6 指针和数组的关系

1[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zWRYhAwZ-1649660664476)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220405025602658.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-krGhH6DH-1649660664477)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220405030409831.png)]

虽然指针里面的a[0]占用4个字节空间,在他赋值给p的时候,会将它最小的地址赋值。即0x 00 00 20 00

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NJ3jt96H-1649660664478)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220405030038007.png)]

2.数组的引用方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HvJSBJjd-1649660664478)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220405033133256.png)]

注意:p 和 a 的不同,p是指针变量,而a是一个常量。所以可以用等号给p赋值,但不能给a 赋值。

p=&a[3]; //正确

a=&a[3]; //错误

方法3:通过指针变量运算加取值的方法来引用数组的元素

int *p;

p = a;

*(p+2)=100;//也是可以的 ,相当于a[2] = 100
解释:p是第0个元素的地址,p+2 是a[2] 这个元素的地址。
对第二个元素的地址取值,即a[2]

方法4:通过数组名+取值的方法引用数组的元素

int a[10];

*(a+2)=100;//也可以是a[2] = 100;

注意:a+2 是 a[2] 的地址。这些地方并没有给 a 赋值

例题:

#include <stdio.h>
int main()
{
    int a[5] = {0, 1, 2, 3, 4};
    int *p;
    p = a; //这一步相当于将数组a的内存地址给了变量 p,之后在调用的时候始终都会指向这个地址。
    printf("a[2] = %d\n", a[2]);
    printf("p[2] = %d \n", p[2]);
    printf("*(p+2)=%d\n", *(p + 2));
    printf("*(a+2)=%d\n", *(a + 2));
    printf("a=%d\n", a);
    printf("a+1=%d\n", a + 1);
    printf("&a=%d\n", &a);
    printf("&a+1=%d\n", &a + 1);
    printf("sizeof(a)%d\n", sizeof(a));
    printf("sizeof(a)%d\n", sizeof(a + 1));

    printf("p = %d\n", p);
    printf("p+2 = %d\n", p + 1);
    return 0;
}

/*
a[2] = 2
p[2] = 2
*(p+2)=2
*(a+2)=2
a=6422016
a+1=6422020
&a=6422016
&a+1=6422036
sizeof(a)20
sizeof(a)8
p = 6422016
p+2 = 6422020
08 - 00 = 8   验证了我们上面的,加了两位,int类型4个字节  加两位 8字节
*/
3、指针的运算

1:指针可以加一个整数,往下指几个它指向的变量,结果还是个地址

​ 前提:指针指向数组的时候 ,加一个整数才有意义。

例:
    int a[10];
	int *p;
	p=a ;
	p+2;//p是a[0]的地址,p+2是&a[2]

​ **假如p保存的地址编号是 2000的话 ,p+2 代表的地址编号就是2008 **

例:
    char buf[10];
	char *q;
	q = buf;
	q+2; //相当于 &buf[2]
	//指针加一个数,他的地址编号取决于这个指针的类型,char +2 也就是2  int +2 也就是8   double型的 也就是 16

假如:q中存放的地址编号是2000的话,q+2代表的地址编号是 2002

2:两个相同类型的指针可以比较大小

前提:只有两个相同类型的指针指向 同一个数组的元素的时候,比较大小才有意义。

指向前面元素的指针  小于  指向后面  元素的指针

#include <stdio.h>
int main()
{
    int a[10];
    int *p, *q, n;
    p = &a[1];
    q = &a[6];
    if (p < q)
    {
        printf("p<q\n");
    }
    else if (p > q)
    {
        printf("p>q\n");
    }
    else
    {
        printf("p=q\n");
    }
    return 0;
}
//结果为p<q  这结果得到的是a1的地址小于a6的地址

3.相同类型的指针可以做减法

指针数组相减,减少的是两个数组之间相隔几个元素,如整数a[0]和a[3] a3-a1 =3 相隔三个元素 12个字节 一个元素4个字节

前提:必须是两个相同类型的指针指向同一个数组的元素的时候,做减法才有意义

​ 做减法的结果是,两个指针指向的中间有多少个元素

  int a[5];
    int *p, *q;
    p = &a[0];
    q = &a[3];
    printf("q-p=%d\n", q - p);
    printf("q=%d\n", q);
    printf("p=%d\n", p);
    printf("q=%d\n", *q);
    printf("p=%d\n", *p);
//结果是3

4:两个相同类型的指针可以相互赋值

​ 注意:只有相同类型的指针才可以相互赋值(*void 类型的除外

int *p;
int *q;
int a;
p=&a; //p保存了a的地址,p指向了变量a
p=q;//用p给q赋值,q也保存了a的地址,必须进行强制类型转换

注意c语言规定数组的名字,就是数组的首地址,就是数组第0个元素的地址

int *p;
int a[10];
p=a; p=&a[0] //这两种赋值方式是等价的

6.1.7 指针数组

1、指针和数组的关系

​ 1:指针可以保存数组元素的地址

​ 2:可以定义一个数组,数组中由若干个相同类型指针变量,这个数组被称为指针数组 int *p[5];//p[0] p[1] 都可以存放整形

指针数组的概念:

​ 指针数组本身就是一个数组,是一个指针数组,是若干个相同类型的指针变量构成的集合

2、指针数组的定义方法

类型说明符 * 数组名 [元素个数];

​ int * p[5];// 定义了一个整型的指针数组p,有5个元素 p[0]~p[5]

​ 每个元素都是int * 类型的变量

	int * p[5];	
	int a;

	p[0]=&a;

	int b[10];

	p[1]=&b[5];
//p[2]、*(p+2)是等价的 ,都是指针数组中的第二个元素
//例:
#include <stdio.h>
int main()
{
    int *p[5];
    int a = 100;
    int b[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
    printf("sizeof(p)  = %d\n", sizeof(p));
    p[0] = &a;
    printf("p[0]=%p\n", p[0]);
    printf("&a =%p\n", &a);
    printf("*p[0]=%d\n", *p[0]);

    p[1] = &b[2];
    printf("*p[1]=%d\n", *p[1]);
    return 0;
}

/*
sizeof(p)  = 40
p[0]=000000000061FDEC
&a =000000000061FDEC
*p[0]=100
*p[1]=3
*/
13 
    #include <stdio.h>
int main()
{
    char *name[5] = {"hello",
                     "china",
                     "beijing",
                     "henan",
                     "anhui"};
    int i;
    for (i = 0; i < 5; i++)
    {
        printf("*name[i] = %s\n",name[i]); //输出的是name[i]的地址
        printf("*name[i] = %d\n", sizeof(*name[i]));
        printf("*name[i] = %c\n", *name[i]);
    }
    return 0;
}

文字常量区存放的都是字符的ascll码的二进制,没有存放在字符数组name中,数组里面存放的都是字符串对应的首地址编号[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lksIpjQf-1649660664479)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406093205483.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2zXifd4Q-1649660664479)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406093433672.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OHo2yC0R-1649660664480)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406093627223.png)]

3、指针数组的分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Z7UkmSK-1649660664480)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406093724932.png)]6.1.8 指针的指针

指针的指针,即指针的地址,

​ 咱们定义一个指针变量本身指针变量占4个字节(32位系统下,64位占8个字节),指针变量也有地址编号

例如:
int a = 0x12345678;
假如:a的地址是0x00002000
int *p;
p =&a;
则p中存放的是a的地址编号即0x00002000

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qugKO56p-1649660664480)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406094445442.png)]

int *p;
int **q;

q =&p;//p保存了a的地址,也可以说q指向了p

则q里面存放的就是0x00003000

int ***m;

m = &q;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-40ylSbfK-1649660664481)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406094819145.png)]

p q m 都是指针变量,都占用4个字节,都存放地址编号,只不过类型不一样而已。

#include <stdio.h>
int main()
{
    int a = 0x12345678;
    int *p;
    int **q;
    int ***m;
    p = &a;
    printf("&a = %p\n", &a);
    printf("p=%p\n", p);
    q = &p;
    printf("&p = %p\n", &p);
    printf("q=%p\n", q);
    m = &q;
    printf("&q = %p\n", &q);
    printf(" m=%p\n", m);

    printf("*P = %x\n", *p);   //一级指针   12345678
    printf("**q=%x\n", **q);   //二级指针   12345678
    printf("***m=%x\n", ***m); //三级指针   12345678

    return 0;
}
//想获取一个指针的地址,就需要二级指针,或者三级四级...

6.1.9 字符串和指针

1.字符串的概念:

​ 字符串就是以’\0’结尾的若干个的字符的集合:比如"helloworld"。

字符串的地址,是第一个字符的地址。如:字符串:“helloworld” 的地址,其实就是字符串中字符’h’ 的地址。

我们可以定义一个字符指针变量保存字符串的地址,比如:char *s =“helloworld”;

2.字符串的存储形式:数组、文字常量区、堆

1、字符串存放在数组中

​ 其实就是在内存中(栈、静态全局区)中开辟了一段空间来存放字符串。

​ char string[100] = “I LOVE C!”;

​ 定义了一个字符数组 string,用来存放多个字符,并且用"I LOVE C!" 给string数组初始化

​ 字符串"I LOVE C!" 存放在string中。

:普通全局数组,内存分配在静态全局区

​ 普通局部数组,内存分配在栈区。

​ 静态数组(静态全局数组、静态局部数组),内存分配在静态全局区

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rc0z9NxA-1649660664481)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406101218607.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gkQNnAlQ-1649660664482)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406101417564.png)]

3.字符串的可修改性

​ 字符串的内容是否可以被修改,取决于字符串存放在哪里。

1.存放在数组中的字符串的内容是可以修改的

​ char str[100] =“I LOVE C!”;

​ str[0] = ‘y’; // 正确可以修改的

​ 注:数组没用const 修饰

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vDiAfe85-1649660664482)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406101954855.png)]

#include <stdio.h>
int main()
{
    //数组中的字符串,存放在栈中的。
    // char str[100] = "I LOVE C!";
    // printf("str=%s\n", str);
    // str[0] = 'y';
    // printf("str=%s", str);
    // return 0;
    //没有用const 修饰

    char *str = "I LOVE C!";
    printf("str=%s\n", str);
    *str = 'y'; //错误,I 存放在文字常量区,不允许被修改
    printf("str=%s\n", str);

    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s8DSU9uy-1649660664482)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406103217764.png)]

#include <stdio.h>
#include <stdlib.h>
int main()
{
    char *str;
    str = (char *)malloc(20);//当str指向堆区的时候,就可以进行修改了,堆区的内容可以修改。文字常量区不可以。
    strcpy(str, "I LOVE C!");
    printf("str = %s\n", str);
    *str = 'y';
    printf("str = %s\n", str);
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7jNSifC7-1649660664482)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406104507888.png)]

4.初始化

1.字符数组初始化:

​ char buf aver[20] = “hello world”;

2.指针指向文字常量区,初始化:

​ char * buf_point = “hello world”;

3.指针指向堆区,堆区存放字符串。

​ 不能初始化,只能先给指针赋值,让指针指向堆区,在使用strcpy、scanf等方法把字符串拷贝到堆区。

char *buf_heap;

buf_heap =(char * )malloc(15);

strcpy(buf_heap,"hello world!);

scanf(“%s,buf_heap”);

5.使用时赋值

1.字符数组:使用scanf 或者 strcpy

char buf[20] = “hello world”

​ buf = “hello kitty”; 错误,因为字符数组的名字是个常量,不能用等号给常量赋值

strcpt(buf,“hello world”); 正确,数组中的内容是可以修改的

scanf(“%s”,buf); // 这个直接输入也可以修改哦

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CcfOcs51-1649660664483)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406111723731.png)]

总结来说:指针指向文字常量区的内容不可以修改,但是能够修改指向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IPcNChQM-1649660664483)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406114101291.png)]字符串和指针总结:

1、指针可以指向文字常量区

​ (1)指针指向的文字常量区的内容不可以修改

​ (2)指针的指向可以改变,既可以给指针变量重新赋值,指针变量指向别的地方。

2、指针可以指向堆区

​ (1)指针指向的堆区的内容可以修改

​ (2)指针的指向可以改变,即可以给指针变量重新赋值,指针变量指向别的地方。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3j7lbsst-1649660664483)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406132249753.png)]

6.1.10 数组指针

1、二维数组

​ 二维数组,有行,有列。二维数组可以看成有多个一维数组构成的,是一个一维数组的集合可以认为二维数组的每一个元素是个一维数组。

例:

​ int a[3] [5]

定义了一个3行5列的一个二维数组。

可以认为二维数组 a 由 3个一维数组构成,每个元素是一个一维数组。

回顾:

​ 数组的名字是数组的首地址,是第0个元素的地址,是个常量,数组名字加1 指向下一个元素

​ 二维数组a中 ,a+1指向下一个元素,即下一个一维数组,即下一行。

#include <stdio.h>
int main()
{
    int a[3][5];

    printf("a=%d\n", a);
    printf("a+1=%d\n", a + 1);
}
//a=6421984
//a+1=6422004   
//2204-1984 = 20    相隔了5个整型元素  一个占4字节   4x5 = 20
2、数组指针的概念

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHJX32IH-1649660664484)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406154213618.png)]

3、数组指针的定义及使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9bxDb49a-1649660664484)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220406171438471.png)]

和指针数组的区别在于一个是数组一个是指针,前者用于指向一个二维或多维数组,后者用来存放若干个相同类型的指针变量的存储集合

#include<stdio.h>
int main(){
     //一维数组指针,主要配合二维数组来用
        int a[3][5];
        int b[6][5];
    int (*p)[5] ;//数组指针的个数必须和我们要调用的二维数组的列数相同
    p = a ;//数组的名字是数组的首地址,是第0个元素的地址,是个常量,数组名字加1 指向下一个元素
    printf("a=%d\n",a);//这是数组指针
    printf("a+1=%d\n",a+1);//可见,当a+1的时候 它会根据数组类型和元素个数叠加 如整型 4个字节  【5】个元素  所以a和a+1相差20字节

    printf("p=%d\n",p); 
    printf("p+1=%d\n",p+1);

    printf("a[0][0]=%d\n",&a[0][0]); //整型的指针加一,会叠加他类型所占的字节
    printf("a[0][0]+1=%d\n",&a[0][0]+1); //加整型的字节也就是 4  ,这里要分清楚整型的指针和数组指针是不一样的
    return 0; 
}

指针数组的用法:

#include<stdio.h>

void fun(int (*p)[5],int x,int y);
int main(){
    int a[3][5] = {
        {1,2,3,4,5},
        {6,7,8,9,10},
        {11,12,13,14,15}
    };
    printf("a[1][2]=%d\n",a[1][2]);
    fun(a,3,5);
    printf("a[1][2]=%d\n",a[1][2]);

       return 0;
}

void fun(int (*p)[5],int x,int y)
{
    p[1][2] = 100;

    }
 
4、各种数组指针的定义

(1)、一维数组指针,加1后指向下个一维数组

​ int(*p)[5];// 注意加括号 不然就是int *p[5] 前者数组指针,后者指针数组。前者代表二维数组的元素只占用4个字节,后者存放了5个整型指针变量,占用20字节。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1WrjgKFv-1649660664484)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408090644478.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EA8sUXj8-1649660664484)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408090706596.png)]

(p+1)[i]相当于p[i+1] 往后指一行

#include<stdio.h>
void fun(int(*p)[4][5])
{
    
}
int main(){
    int a[3][4][5];
    printf("a=%p\n",a);
    printf("a+1=%p\n",a+1);//a和a+1 地址编号相差80个字节
    //验证了a+1 跳一个4行5列的一个二位数组
    
    printf("&a=%p\n",&a);
    printf("&a+1=%p\n",&a+1);//a和a+1 地址编号相差240个字节
    //验证了&a+1 指向数组指针 跳三个4行5列的一个二位数组

    int (*p)[4][5];
    p =a;
    printf("p=%p\n",p);
    printf("p+1=%p\n",p+1);//p和p+1 地址编号相差也是80个字节  (p+1)[i]相当于p[i+1] 往后指一行
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N0xp7jlD-1649660664485)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408092842379.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UT60v2sD-1649660664485)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408090804532.png)]

8、数组名字取地址:变成 数组指针

一维数组名字取地址,变成一维数组指针,即加1跳一个一维数组

​ int a[10];

a+1 跳一个整型元素,是a[1]的地址

a和 a+1 相差一个元素,4个字节。

&a 就变成了一个一维数组指针,是 int(*p)[10]类型的。

(&a)+1 和&a相差一个数组即10个元素即40个字节

#include <stdio.h>
int main()
{
    int a[10];
    printf("a=%p\n", a);
    printf("a+1=%p\n", a + 1); // a和a+1相差4个字节

    printf("&a =%p\n", &a);    //数组指针 ,取地址的a+1
    printf("&a+1=%p", &a + 1); //数组取地址加1  等同于int(*p)[10]; 等于跳过了10个元素,单个元素4个字节  也就是40字节  。两者相差40
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uSJ5iinn-1649660664486)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220407113128193.png)]

在运行程序时,大家会发现a和&a所代表的地址编号是一样的,即他们指向同一个存储单元,但是a和&a的指针类型不同

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eKwO1xKE-1649660664486)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220407115017603.png)]

#include <stdio.h>
int main()
{
    // int a[10];
    // printf("a=%p\n", a);
    // printf("a+1=%p\n", a + 1); // a和a+1相差4个字节

    // printf("&a =%p\n", &a);    //数组指针 ,取地址的a+1
    // printf("&a+1=%p", &a + 1); //数组取地址加1  等同于int(*p)[10]; 等于跳过了10个元素,单个元素4个字节  也就是40字节  。两者相差40
    // return 0;
    int a[4][5];
    printf("a = %d\n", a);
    printf("a+1= %d\n", a + 1); // a是int*类型的指针 即+1等于跳过了1行5列的元素 一个元素4个字节  4x5 = 20个字节

    //对a取地址变成&a 即从int *类型的指针变成了数组指针
    printf("&a=%d\n", &a);         //变成了 int(*p)[4][5]
    printf("&a+1 = %d\n", &a + 1); //&a和&a+1相差了 80个 字节
    //&a和&a+1相当于相隔了一个二维数组也就是相差了4行5列,一共20个元素,每个元素4字节,20x4 = 80个字节
    int b[3][4][5];
    printf("a = %d\n", b);
    printf("a+1= %d\n", b + 1);
    return 0;
}

总结:c语言规定,数组名字取地址,变成了指针数组。加一跳一个数组

9、数组名字和指针变量得区别

int a[5];

int *p;

p=a;

相同点:

a是数组的名字,是a[0]的地址,p=a即保存了a[0]的地址,即a和p都指向a[0],所以在引用数组元素的时候,a和p等价

引用数组元素回顾:

​ a[2]、*(a+2)、p[2]、 *(p+2)都是对数组a中a[2]元素的引用。

#include <stdio.h>
int main()
{
    int a[5] = {0, 1, 2, 3, 4};
    int *p;
    p = a;
    printf("a=%p\n", a);
    printf("a+1=%p\n", a + 1);
    printf("a=%d\n", &a);
    printf("a+1=%d\n", &a + 1);
    printf("p=%p\n", p);

    printf("a[2] = %d\n", a[2]);
    printf("*(a+2)= %d\n", *(a + 2)); //不管在一位数组还是二维或者多维  a[2] 与 *(a+2)都是等价的

    printf("p[2]=%d\n", p[2]);
    printf("*(p+2)= %d", *(p + 2));
    return 0;
}
#include <stdio.h>
int main()
{
    int a[5] = {0, 1, 2, 3, 4};
    int *p;
    p = a;

    p = &a[3];
    printf("*p=%d\n", *p);

    // a=&a[3];  等号左边必须是一个变量而 a是一个常量
    
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wkb17opj-1649660664486)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220407141535634.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a845xe8E-1649660664487)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220407142940311.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cENmLf1p-1649660664487)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220407142830288.png)]

#include <stdio.h>
int main()
{
    int a[5] = {0, 1, 2, 3, 4};
    int *p;
    p = a;

    printf("a=%d\n", a);
    printf("&a= %d\n", &a); // int (*p)[5]
    printf("a+1=%d\n", a + 1);

    printf("&a+1=%d\n", &a + 1);

    printf("&p =%d\n", &p);        // int **
    printf("&p+1 = %d\n", &p + 1); //在64位系统下取int指针得地址一位占8字节  所以&p+1比&p 多8字节
    //   a=6422016
    // &a= 6422016
    // a+1=6422020
    // &a+1=6422036
    // &p =6422008
    // &p+1 = 6422016
}

10、数组指针取*

数组指针>取 * ,并不是取值的意思,而是指针的类型发生变化:

一维数组指针取*,结果为它指向的一维元素第0个元素的地址,它们还是指向同一个地方。

二维数组指针取 * ,结果为一维数组指针,它们还是指向同一个地方。

三维数组指针取 * ,结果为二维数组指针,它们还是指向同一个地方。

多维数组以此类推

这里不用迷,就是说给数组指针取*不管是几维数组传给了这个指针对这个指针变量取** 的值都是第0个元素的地址,二维数组是【0】【0】个元素的地址+一也就是【0】【1】的地址,三维以此类推,二不加**就是数组第【0个元素的地址】,在二维数组也就是【0】【0】的地址,+1也就是【1】【0】的地址,两者是不相同的

#include <stdio.h>
int main()
{
    int a[3][5];
    int(*p)[5];
    p = a;

    printf("a =%d\n", a);         // a是数组的名字,是数组中第0个一维数组得首地址
    printf("a+1 =%d\n", a + 1);   //跳一行,一行5个元素 ,一个元素4字节,也就是20个字节
    printf("*a =%d\n", *a);       //*a 是第0行第0列元素的地址,即&a[0][0]
    printf("*a+1 =%d\n", *a + 1); //*a+1 是&a[0][1] 的地址
    printf("             \n");
    printf("p=%d\n", p);
    printf("p+1=%d\n", p + 1);
    printf("*p = %d\n", *p);
    printf("*p+1=%d\n", *p + 1);
    printf("    \n");
    
 	printf("&a[0][0]%d\n", &a[0][0]);
    
    printf("&p=%d\n", &p); //当前对指针取地址结果是指针的指针  +1 在64位系统下  int 占8字节  所以 &p+1大*p 8字节
    printf("&p+1=%d\n", &p + 1);

    printf("&a=%d\n", &a); //当前对数组取地址结果是数组指针 为int(*)[3][5]  所以&a和&a+1 相差3x5x4 = 60  个字节
    printf("&a+1=%d\n", &a + 1);
    return 0;
}

a =6421984
a+1 =6422004
*a =6421984
*a+1 =6421988

p=6421984
p+1=6422004
*p = 6421984
*p+1=6421988

&a[0][0]6421984
&p=6421976
&p+1=6421984
&p=6421984
&p+1=6422044

6.1.11 指针和函数的关系

1.指针作为函数的参数

咱们可以给一个函数传一个 整型、字符型、浮点型的数据,也可以给函数传一个地址。

例子

不传函数地址
//指针作为函数的参数
#include <stdio.h>
void swap(int x, int y) //函数括号里面的值是局部变量
{
    int temp;
    temp = x;
    x = y;
    y = temp;
}
int main()
{
    int a = 10;
    int b = 20;

    swap(a, b);
    printf("a=%d b=%d\n", a, b);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mZRuiC8T-1649660664487)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220407172736783.png)]

传函数地址
//指针作为函数的参数
#include <stdio.h>
void swap(int *p, int *p2, int x, int y) //函数括号里面的值是局部变量
{
    int temp;
    temp = *p;
    *p = *p2;
    *p2 = temp;
}
int main()
{
    int a = 10;
    int b = 20;
    int *p;
    p = &a;
    int *p2;
    p2 = &b;
    swap(p, p2, a, b);
    printf("a=%d b=%d\n", a, b);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dsBUAWLP-1649660664488)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220407173133723.png)]

//指针作为函数的参数
#include <stdio.h>
void swap(int *p, int *p2) //函数括号里面的值是局部变量
{
    int *p0;
    p0 = p;
    p = p2;
    p2 = p0;
}
int main()
{
    int a = 10;
    int b = 20;

    swap(&a, &b);
    printf("a=%d b=%d\n", a, b);
}

结果不变

总结:要想改变主调函数中变量得值,必须传变量得地址,而且还得通过*+地址去赋值

#include<stdio.h>


void fun(char *q){
    q = "hello kitty";
}
int main(){
    char *p ="hello world!";
    fun(p);
    printf("p=%s\n",p);
    return 0;
}



#include<stdio.h>

void fun(char **q){
    *q = "hello kitty";
}
int main(){
    char *p = "helloworld! ";
    fun(&p);

    printf("p = %s\n",p);
    return 0;
}


总结一句话:要想改变主调函数中变量得值,必须传变量得地址,而且还得通过*+地址去赋值,无论这个变量是什么类型的

传数组

给函数传数组:

​ 给函数传数组的时候,没法一下将数组的内容作为整体直传进去。

​ 只能传数组名进去,数组名就是数组的首地址,即只能把数组的地址传进去。

​ 也就是说,只能传一个4个字节大小的地址编号进去

例:传一维数组的地址

 #include<stdio.h>
void fun(int p[]){
    printf("p[2]=%d\n",p[2]);
    *(p+3) =100;
   
}

// void fun(int *p){ int *p  和int p[] 两者等价
//     printf("p[2]=%d\n",p[2]);
//     *(p+3) =100;
   
// }
int main(){
    int a[10] = {1,2,3,4,5,6,7,8,9,0};
    fun(a);
    printf("a[3]=%d\n",a[3]);
    return 0;
}

例:传二维数组的地址

#include<stdio.h>
//void fun(int (*p)[4],int x,int y){ 两者等价
void fun(int p[][4],int x,int y){
    printf("p[1][2]=%d\n",p[1][2]);
    p[0][1] =  100; 
    for(int i =0;i<x;i++){
        for(int j = 0;j<y;j++){
            printf("i=%d j=%d p[i][j]=%d\n",i,j,p[i][j]);
        }
    }
}
int main(){
    int a[3][4]={
        {1,2,3,4},
        {5,6,7,8},
        {9,10,11,12}
    };
    fun(a,3,4);
    printf(" a[0][1] =%d\n", a[0][1]);
    return 0;
}
传指针数组
#include<stdio.h>
//void fun(char *q[],int x) //两者等价
void fun(char **p,int x){
    for(int i=0;i<x;i++){
        printf("p[i]=%s\n",*(p+i));
    }
}
int main(){
    char * p[3] ={"hello","world","kitty"};//p[0] p[1] p[2] 是char*
    fun(p,3);//p 就是  &p[0]的地址
    return 0;

}
2.指针作为函数的返回值

一个函数可以返回整型数据、字符数据、浮点型的数据,也可以返回一个指针

#include <stdio.h>
char *fun(void)
{

    // char str[100] = "hello world!"; //这种情况下另一个函数调用会报错,因为str 是局部变量,局部变量得作用范围在这个函数。
    //可以写成 要看指针指向得内存   局部变量会被释放,静态区不会  文字常量区也不会
    // static char str[100] = "hello world!";
    char *str = "hello world!!"; //指针的指针
    return str;
}
int main()
{
    char *p;
    p = fun(); //等于文字常量区得另一个指针也就是 char **p 了
    printf("p=%s\n", p);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *fun(void)
{
    char *str;
    str = (char *)malloc(100);
    strcpy_s(str, 100, "helloworld");
    return str;
}
int main()
{
    char *p;
    p = fun();
    printf("p=%s\n", p);
    free(p);
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g1xntWTx-1649660664488)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408095825301.png)]

3.指针保存函数得地址(函数指针)
1、函数指针得概念

咱们定义的函数,在运行程序的时候,会将函数的指令加载到内存得代码段。所以函数也有起始地址。

c语言规定:函数的名字就是函数的首地址,即函数的入口地址

咱们就可以定义一个指针变量,来存放函数的地址。

这个指针变量就是函数指针变量

2、函数指针的用处

函数指针用来保存函数的入口地址

在项目开发中,我们经常需要编写或者调用带函数指针参数的函数。

比如LInux系统中创建多线程得函数,他有个参数就是函数指针,接收线程函数得入口地址,即线程创建线程成功后,新的任务执行线程函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xElebZYM-1649660664488)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408101958309.png)]

3、函数指针变量得定义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pfGDMuaL-1649660664489)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408102813317.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mXdPOGzD-1649660664489)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408103031290.png)]

4、调用函数的方法
1.通过函数的名字去调函数(最常用的)

int max(int x , int y)

{

}

int main()

{

​ int num;

​ num =max(3,5);

}

2、可以通过函数指针变量去调用
#include <stdio.h>
int max(int x, int y)
{
    int temp;
    if (x > y)
    {
        temp = x;
    }
    else
    {
        temp = y;
    }
    return temp;
}
int min(int x, int y)
{
    int temp1;
    if (x > y)
    {
        temp1 = y;
    }
    else
    {
        temp1 = x;
    }
    return temp1;
}

int main()
{
    int (*p)(int, int);
    int num;
    num = max(10, 20);//通过函数名调用
    printf("num =%d\n", num);
    p = min;//通过函数指针调用
    num = (*p)(10, 20); //等价于  num =min(10,20);  加不加*都可以
    printf("num = %d\n", num);
    return 0;
}
5、函数指针数组

概念:由若干个相同类型的函数指针变量构成的集合,在内存中连续的顺序存储.

函数指针数组是个数组,他的每个元素都是一个函数指针变量

函数指针数组的定义

​ *类型名(数组名[元素个数])(形参列表)

​ *int(p[5])(int,int);

​ 定义了一个函数指针数组,有5个元素p[0]~p[4],每个元素都是函数指针变量,每个函数指针变量指向的函数,必须有整型的

返回值,两个整型参数。

#include<stdio.h>
int min(int x, int y)
{
    int temp1;
    if (x > y)
    {
        temp1 = y;
    }
    else
    {
        temp1 = x;
    }
    return temp1;
}
int max(int x, int y)
{
    int temp1;
    if (x > y)
    {
        temp1 = y;
    }
    else
    {
        temp1 = x;
    }
    return temp1;
}
int add(int x,int y) {
    return x + y;
}
int del(int x, int y) {
    return x-y;
}
int mux(int x, int y) {
    return x * y;
}
int main(int x, int y) {
    //我们知道函数的名字就是函数的首地址
    int (*p[5])(int, int) = { max,min,mux,del,add };
    int num;
    num = (*p[2])(10, 20);
    printf("num = %d", num);


}
6、函数指针的应用举例

函数指针变量作为函数的参数

#include<stdio.h>
int add(int x, int y) {
    return x + y;
}
int del(int x, int y) {
    return x - y;
}
int mux(int x, int y) {
    return x * y;
}
int dive(int x, int y) {
    return x / y;
}
int process(int(*p)(int, int), int x, int y) {
    int ret;
    ret = (*p)(x, y);
    return ret;
}
int main(int x, int y) {
    int num;
    num = process(add, 10, 20);
    printf("num = %d\n", num);

    num = process(mux, 10, 20);
    printf("num = %d\n", num);

    return 0;
}

总结来说一句话:函数指针变量,就是一个指针变量,他就是8个字节(32位系统下为4字节)

6.1.12 经常容易混淆的指针概念

第一组:

1、int *a[10];// 这是一个指针数组,共存放10个元素,一个元素8字节,a占了80个字节。

这是一个指针数组,数组a中有10个整型的指针变量

​ a[0]~a[9] ,每个元素都是int *类型的指针变量

2、int (*a)[10];//数组指针本质还是指针,它指向数组里面的元素,也就是4个字节

​ 数组指针变量,他是一个指针变量。它占4个字节,存地址编号。

​ 它指向一个数组,它加一的话,指向下一个数组。

​ 3、int **p

​ 这是个指针的指针,保存指针变量的地址。

​ 它经常用来保存指针的地址:

​ 常见用法1:

​ int **p

​ int *q;

​ p = &q;

​ 常见用法二:

​ int **p;

​ int *q[10];

分析:q是指针数组的名字,是指针数组的首地址,是q[0]的地址。

​ *q[0]是一个int 类型的指针。 所以q[0]指针变量的地址,是int * * 类型的。

p = &q[0] ; 等价于p =q;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ai2OXkhH-1649660664489)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408151535767.png)]

6.1.13 特殊指针

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N1pkVFDp-1649660664490)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408152810278.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NLkaW0Du-1649660664490)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408152947882.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V75V7tfy-1649660664491)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408154220760.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rg9fIKQt-1649660664491)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220408154446270.png)]

6.1.14 main函数传参

#include <stdio.h>
int main(int argc, char const *argv[])
{
    int i;
    printf("argc= %d\n", argc);
    for (i = 0; i < argc; i++)
    {
        printf("argc[%d]=%s\n", i, argv[i]);
    }

    return 0;
}

//argc[0]=d:\cyy\函数指针\main函数传参
//在linux环境下我们进入这个目录 然后执行可执行文件 exe  加空格 输入我们想要传递的参数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jWR6ua98-1649660664492)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409120329217.png)]

第七章 动态内存申请

7.1动态分配内存的概述

​ 在数组一章中,介绍过数组的长度是预先设定好的,在整个程序中固定不变,但是实际的编程中,往往会发生这种情况

即所需的**内存空间取决于实际输入的数据**,而无法预先确定。为了解决上述问题,C语言提供了一些内存管理函数,这些内存

管理函数可以按需要动态的分配内存空间,也可把不再使用的空间回收再次利用。

7.2静态分配、动态分配

静态分配

  1. 在程序的编译或运行的过程中,按事先规定大小分配内存空间的分配方式。int a[10]
  2. 必须事先知道所需空间的大小
  3. 分配在栈区或全局变量区,一般以数组的形式
  4. 按计划分配。

动态分配

  1. 在程序运行过程中,根据需要大小自由分配所需空间。
  2. 按需分配
  3. 分配在堆区,一般使用特定的函数进行分配

7.3动态分配函数

头部库文件 stdlib.h

1、malloc 函数

函数原型:void * malloc(unsigned int size);

功能说明:

​ 在内存的动态存储区(堆区)中分配一块长度为size字节的连续区域,用来存放类型说明符指定的类型。函数

原型返回的void*指针,使用时必须做相应的强制类型转换,分配的内存空间内容不确定,一般使用memset初始化。

**返回值:**分配空间的起始地址(分配成功)

​ null (分配失败)

注意:

​ 1、再调用malloc之后,一定要判断一下,是否申请内容成功

​ 2、如果多次malloc申请的内存,第一次和第二次申请的内存不一定是连续的

char *p;

p = (char *)malloc(20);//*malloc默认是void 类型,转换成你想要的字符型需要强转。

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int *p;
    int i, n;
    printf("请输入你要申请int数组的元素个数:\n");
    scanf_s("%d", &n, 4);
    p = (int *)malloc(n * 4);
    if (p == NULL)
    {
        printf("malloc is null\n");
        return 0;
    }

    for (i = 0; i < n; i++)
    {
        p[i] = i;
        printf("p[%d]=%d\n", i, p[i]);
    }
    free(p);
    return 0;
}

2、free函数(释放内存空间)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FV5DQw5e-1649660664492)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409130855489.png)]

3、calloc函数

​ 头文件:#include<stdlib.h>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XwMbhDPr-1649660664493)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409131147121.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QLA6UGqz-1649660664493)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409131405670.png)]

4、realloc函数(重新申请内存)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jb5Vw8m0-1649660664493)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409131646615.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TEEDvBHa-1649660664493)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409131658733.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OGmjiyux-1649660664494)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409133819419.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QCCJzAII-1649660664494)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409133825113.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9sVyGk0C-1649660664494)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409133956445.png)]

7.4 内存泄漏

内存泄漏的概念:

​ 申请的内存,首地址丢了,找不了,再也没法使用了,也没法释放了,这块内存就泄露了。

内存泄漏 例1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P0HUyuyy-1649660664495)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409162418755.png)]

内存泄漏 例2:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mhQr1ZtW-1649660664495)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409162824613.png)]

内存泄漏1 解决方案:

其实就是在方法的后面清理一下 加上 free§;函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rTALpP6u-1649660664495)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409162923834.png)]

内存泄漏2 解决方案:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BRLpRL5K-1649660664496)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409163047423.png)]

总结:申请的内存,一定不要把首地址给丢了,在不用的时候一定要释放内存。

第八章 字符串处理函数

#pragma 指令的作用是:用于指定计算机或者操作系统特定的编译器功能。

#pragma warning(disable:4996) 在c文件开始处写上这句话,即告诉编译器忽略4996警告,strcpy、scanf等一些不安全的

标准C库函数在vs 中可以用了。

8.1 测字符串长度函数

头文件:#include<string.h>

函数定义:size_t strlen(const char *a)

函数功能:

​ 测字符指针 s 指向的字符串中字符的个数,不包括 ‘/0’

返回值:字符串中字符个数。

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)

int main() {
	
	char str1[20] = "hello";
	char* str2 = "hello";
	printf("sizeof(str1)=%d\n", sizeof(str1));
	printf("sizeof(str2)=%d\n", sizeof(str2));

	printf("strlen(str1)=%d\n", strlen(str1));
	printf("strlen(str2)=%d\n", strlen(str2));
	return 0;



}
sizeof(str1)=20
sizeof(str2)=8
strlen(str1)=5
strlen(str2)=5

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LztD2tiA-1649660664496)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409175429156.png)]

8.2 字符串拷贝函数

头文件:#include<stirng.h>

函数的声明:**char *strcpy(char dest,const char src);

函数的说明:

拷贝src指向的字符串到dest 指针指向的内存中,'\0’也会拷贝

函数的返回值:

​ 目的内存的地址

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char str[100] = "aaaaaaaaaaaaaaaaaaaaaaaaaa";
    strcpy(str, "hello");
    printf("str=%s\n", str);
    printf("str+6=%s\n", str + 6);//因为会将'\0'打入所以后面的打不出来,需要加6才能打出来
    return 0;
}
str=hello
str+6=aaaaaaaaaaaaaaaaaaaa

注意:在使用此函数的时候,必须保证dest指向的内存空间足够大,否则会出现内存污染。

**char strncpy(char * dest,const char src,size_t n);

函数的说明:

将src指向的字符串前n个字节,拷贝到dest指向的内存中

返回值:目的内存的首地址

注意:

​ 1、strcpy 不拷贝 ‘\0’

​ 2、 **如果n大于src指向的字符串中的字符个数,则在 dest 后面填充n-strlen(src)**个’\0’

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[100] = "aaaaaaaaaaaaaaaaaaaaaa";
    strncpy(buf, "helloworld", 5);//因为不会打印'\0'所以可以打出来全部,只是把前几个数据替换
    printf("buf=%s\n", buf);
    return 0;
}
buf=helloaaaaaaaaaaaaaaaaa
#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[100] = "aaaaaaaaaaaaaaaaaaaaaaaaaa";
    int len;
    len = strlen(buf);
    strncpy(buf, "helloworld", 15);
    printf("buf=%s\n", buf);
    for (int i = 0; i < len; i++)
    {
        printf("buf[%d]=%c\n", i, buf[i]);
    }
    return 0;
}
buf=helloworld
buf[0]=h
buf[1]=e
buf[2]=l
buf[3]=l
buf[4]=o
buf[5]=w
buf[6]=o
buf[7]=r
buf[8]=l
buf[9]=d
buf[10]=
buf[11]=
buf[12]=
buf[13]=
buf[14]=
buf[15]=a
buf[16]=a
buf[17]=a
buf[18]=a
buf[19]=a
buf[20]=a
buf[21]=a
buf[22]=a
buf[23]=a
buf[24]=a
buf[25]=a

8.3 字符串追加函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9wzQTDsw-1649660664497)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409194234637.png)]

注意:

追加的时候会追加’\0’

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{

    char buf[100] = "aaa\0aaaaaaaaaa";//加\0意思是追加的时候从前三个开始追加

    strcat(buf, "helloworld");
    printf("buf=%s\n", buf);
 
    return 0;
}

buf=aaahelloworld

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WiIG3mey-1649660664497)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220409200952976.png)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char str[100] = "aa\0aaaaaaaaaaaaaaaaa";//加\0意思是追加的时候从前三个开始追加 ,如果这个函数没有添加\0那么后面的内容也能打印出来,如果添加了则不会
    char *src = "hello";
    strncat(str, src, 3);//不论n是否大于src的字节都会添加\0,如果大于会将src字符的内容输出。
    printf("str = %s\n", str); 
    return 0;
}
str = aahello

结果是 aahello

验证了追加字符串的时候追加 ‘\0’

8.4 字符串比较函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yhER3HG4-1649660664498)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410124711183.png)]

注意:比较的是ascll码

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char *str1 = "hello world!";
    char *str2 = "hello kitty!";

    int ret;
    ret = strcmp(str1, str2);
    if (ret > 0)
        printf("str1>str2");
    else if (ret < 0)
        printf("str1<str2");
    else
        printf("str1=str2");
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RkKbePJI-1649660664498)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410125423719.png)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char *str1 = "hello world!";
    char *str2 = "hello kitty!";

    int ret;
    ret = strncmp(str1, str2, 5);
    if (ret > 0)
        printf("str1>str2");
    else if (ret < 0)
        printf("str1<str2");
    else
        printf("str1=str2");
}

8.5 字符查找函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6iXMrbhZ-1649660664498)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410125738444.png)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char *str1 = "hello world!saadtyujnn";
    char *p;

    p = strchr(str1, 'l');
    if (p == NULL)
    {

        printf("没有你要找的i那个字");
        return 0;
    }
    printf("p-str=%d\n", p - str1);
    printf("*p=%c\n", *p);
}

p-str=2
*p=l

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r06P30iM-1649660664498)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410155232175.png)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char *str1 = "hello world!saadtyujnn";
    char *p;

    p = strrchr(str1, 'n');
    if (p == NULL)
    {

        printf("没有你要找的i那个字");
        return 0;
    }
    printf("p-str=%d\n", p - str1);
    printf("*p=%s\n", str1);
}
p-str=21
*p=hello world!saadtyujnn

8.6 字符串匹配函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DEMuWWtn-1649660664499)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410155910634.png)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char str1[100] = "defjk$#$sadsadas$#$fjka";
    char str2[100] = "$#$";
    char *p;
    p = strstr(str1, str2); //此处返回的是找到的 str1中匹配的位置
    if (p == NULL)
    {
        printf("没有你要查找的字符串\n");
        return 0;
    }
    printf("p-str1=%d\n", p - str1);
    return 0;
}
//字符串中找字符串 函数
//p-str1=5

8.7 空间设定函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Zjkt2i8-1649660664499)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410194032528.png)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{

    char str[100] = "helloworld";
    //一般用来初始化一块内存
    // memset(str, '\0', 100);
    printf("str=%s\n", str);
    memset(str, 'a', 5);
    printf("str=%s\n", str);

    return 0;
}
str=helloworld
str=aaaaaworld

8.8 字符串转换数值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y2LI4cIz-1649660664499)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410202940678.png)]

long atol(const char *nptr);将字符串转换为一个长整型的数

double atof(const char *nptr); 将字符串转换为一个浮点型的数

8.9 字符串切割函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NbmSksXn-1649660664500)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410203521142.png)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{

    char str[100] = "xiaoming:21,,,.男.女,北京:haidian";
    char *p[7];
    int i = 0, j;
    printf("str=%s\n", str);
    p[i] = strtok(str, ":,.");
    printf("p[%d]=%s\n", i, p[i]);
    printf("str=%s\n", str);
    //如果已经切过,想要在切就要传个null
    while (p[i] != NULL)
    {
        i++;
        p[i] = strtok(NULL, ":,.");
    }

    for (j = 0; j < i; j++)
    {
        printf("p[%d]=%s\n", j, p[j]);
    }
    printf("p[1]+3= %s\n", p[1] + 3);//注意如果str字符串中出现了连续的几个delim中的字符,则只将第一个字符变成'\0' 
    return 0;
}
str=xiaoming:21,,,..,北京:haidian
p[0]=xiaoming
str=xiaoming
p[0]=xiaoming
p[1]=21
p[2]=男
p[3]=女
p[4]=北京
p[5]=haidian
p[1]+3= ,,.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ywrxvJK9-1649660664500)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410205140728.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tMPgpiht-1649660664500)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410205653235.png)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int msg_deal(char *msg_src, char *msg_done[], char *str)
{
    int i = 0;
    msg_done[i] = strtok(msg_src, ",");
    while (msg_done[i] != NULL)
    {
        i++;
        msg_done[i] = strtok(NULL, str);
    }
    return i;
}
int main()
{

    char s[100] = "+CMGR:REC UNREAD,+8617633722460,98/10/01,18:22:11+00,ABCdefGHI";
    char *p[6];
    int num, i;
    num = msg_deal(s, p, ",");
    printf("num=%d\n", num);
    for (i = 0; i < num; i++)
    {
        printf("p[%d]=%s\n", i, p[i]);
    }
    printf("手机号=%s\n", p[1] + 3); //相当于前进三个元素,去掉了+86
    printf("日期=%s\n", p[2]);
    *(p[3] + 8) = '\0'; // p[3]是18:22:11+00的地址 +8 相当于到+,将+变成、0,后面的就不打印了
    printf("时间=%s\n", p[3]);
    printf("内容=%s\n", p[4]);
    return 0;
}
num=5
p[0]=+CMGR:REC UNREAD
p[1]=+8617633722460
p[2]=98/10/01
p[3]=18:22:11+00
p[4]=ABCdefGHI
手机号=17633722460
日期=98/10/01
时间=18:22:11
内容=ABCdefGHI

8.10 格式化字符串操作函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-csaMnNz8-1649660664500)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220410220600692.png)]

sprintf

#include <stdio.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[100];
    sprintf(buf, "%d:%d:%d:%d", 2000, 10, 1, 101); //经常用来写网络数据包
    printf("buf=%s\n", buf);
    return 0;
}
buf=2000:10:1:101

sscanf

#include <stdio.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[100];
    sprintf(buf, "%d:%d:%d:%d", 2000, 10, 1, 101); //经常用来写网络数据包
    printf("buf=%s\n", buf);

    int a, b, c, d;
    char buf1[100];
    sscanf(buf, "%d:%d:%d:%d", &a, &b, &c, &d);
    printf("a=%d\n", a);
    printf("b=%d\n", b);
    printf("c=%d\n", c);
    printf("d=%d\n", d);
    return 0;
}
sscanf高级用法1

1、跳过数据:%s 或 %*d

​ 例如:sscanf(“1234 5678”,“%*d %s”,buf);

sscanf默认碰到空格终止


#include <stdio.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[20];
    int num;
    sscanf("1234 56 78", "%*d %*d %s", buf); //跳过1234 然后隔一个空格获取字符串
    printf("buf=%s\n", buf);

    sscanf("123 45678", "%*s %d", &num);
    printf("buf=%d\n", num);

    sscanf("1234 5678", "%*d %d", &num);
    printf("buf=%d\n", num);
    return 0;
}
buf=78
buf=45678
buf=5678
sscanf高级用法2

2、读指定宽度的数据:%[width]s

例:sscanf(“12345678”,“%4s”,buf);


#include <stdio.h>
#pragma warning(disable : 4996)
int main()
{

    // sscanf  可以指定数组的宽度
    char buf[20];
    int num;
    sscanf("12345678", "%s", buf);
    printf("buf=%s\n", buf);

    sscanf("12345678", "%5s", buf);
    printf("buf=%s\n", buf);

    sscanf("12345678", "%3d", &num);
    printf("num=%d\n", num);

    return 0;
}
buf=12345678
buf=12345
num=123
sscanf高级用法3

3、支持集合操作:只支持获取字符串

%[a-z] 表示匹配a到z中任意字符(尽可能的多匹配)

#include <stdio.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[10];
    sscanf("abdw345mnytUTadf", "%[a-z]", buf);
    printf("buf=%s\n", buf);
    sscanf("abdz w345mnytUTadf", "%[a-z]", buf);
    printf("buf=%s\n", buf);

    sscanf("abdewzw345mnytUTadf", "%[a-f]", buf);
    printf("buf=%s\n", buf);
}
buf=abdw
buf=abdz
buf=abde

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wE8mWZeQ-1649660664501)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220411100141236.png)]

#include <stdio.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[20];
    //匹配%[ad05Fk]遇到不在这个范围的字符则停止输入
    sscanf("ad05Fkl78adf9Faljs", "%[ad05Fk]", buf); //一旦不在adf这个范围就停止输入
    printf("buf=%s\n", buf);
    return 0;
}
buf=ad05Fk
#include <stdio.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[20];
    //匹配%[^k]遇到这个字符则停止输入
    sscanf("ad05Fkl78adf9Faljs", "%[^k ]", buf); //一旦遇到k字符就停止获取
    printf("buf=%s\n", buf);

    sscanf("ad0 5Fkl78adf9Faljs", "%[^k]", buf); //空格也能打印出来,遇到k则停止
    printf("buf=%s\n", buf);
    return 0;
}
buf=ad05F
buf=ad0 5F
sscanf高级用法4
#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[20];
    sscanf("asdf#sdjh@djkd", "%*[^#]%*c%*[^@]%*c%s", buf);
    printf("buf=%s\n", buf);

    return 0;
}
buf=djkd

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nm4DC4LE-1649660664501)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220411114132521.png)]

1.实现strlen函数功能

#include <stdio.h>
#pragma warning(disable : 4996)
unsigned int my_strlen(const char *s)
{
    char *p = s;
    while (*p != '\0')
    {
        p++;
    }
    return p - s;
}

int main()
{
    int num;
    num = my_strlen("helloworld");

    printf("num = %d\n", num);
}

2、实现strcpy函数功能

#include <stdio.h>
#pragma warning(disable : 4996)
// strcpy功能的实现
char *my_strcpy(char *dest, const char *src)
{
    char *p1 = dest;
    const char *p2 = src;
    while (*p2 != '\0')
    {
        *p1 = *p2;
        p1++;
        p2++;
    }
    *p1 = '\0';
    return dest;
}

int main()
{
    char buf[100];
    // char *bufs;
    /*bufs =*/my_strcpy(buf, "hello world");

    printf("buf=%s\n", buf);
    // printf("buf=%s\n", bufs);

    return 0;
}
#include <stdio.h>
#pragma warning(disable : 4996)
// strcpy功能的实现

int my_atoi(const char *str)
{
    const char *s = str;
    int temp = 0;

    while (*s != '\0')
    {
        temp = temp * 10 + (*s - '0');
        s++;
    }
    return temp;
}
int main()
{
    int num;
    char buf[100] = "123456789";
    printf("buf=%s\n", buf);
    num = my_atoi(buf);
    printf("num =%d\n", num);
    return 0;
}
buf=123456789
num =123456789

4、使用sscanf读取"[ti:简单爱]" ":“号与”]"之间的内容


#include <stdio.h>
#pragma warning(disable : 4996)
// strcpy功能的实现

int main()
{
    char buf[100] = "[ti:简单爱]";
    char buf1[100];
    sscanf(buf, "%*[^:]%*c%[^]]", buf1);
    printf("buf1=%s\n", buf1);
}
buf1=简单爱

5、使用 sscanf读取"[02:06:85]" 02(代表分钟) 06(代表秒) 到整型变量min 、 sec 中

#include <stdio.h>
#pragma warning(disable : 4996)
// strcpy功能的实现

int main()
{
    int min, sec;
    sscanf("[02:06.85]", "[%2d:%2d", &min, &sec);
    printf("&min=%02d\n", min); // 02d  打印前两位  没有则用0填充
    printf("&min=%02d\n", sec);
}
&min=02
&min=06

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1e4qXAoa-1649660664501)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220411142500984.png)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
// strcpy功能的实现

int main()
{
    char *str = "helloworldhelloworldhelloworldhelloworld";
    int num = 0;
    char *p;
    char *q = str;
    while ((p = strchr(q, 'w')) != NULL)
    {
        num++;
        printf("第%d个w的位置:%d\n", num, p - str); //因为str一直指向元素的开始,所以p-str
        q = p + 1;                                  // p+1是找到的p 元素的下一个位置
    }
    printf("总共找到%d个w\n", num);
    return num;
}1个w的位置:52个w的位置:153个w的位置:254个w的位置:35
总共找到4个w

8.11 const:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Pv78gfZ-1649660664502)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220411105613475.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BVFirm1O-1649660664502)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220411105920944.png)]

char buf[20] = "helloworld";
    const char *str = buf;
    strcpy(str, "hello kitty!");//能指向不能直接修改
    //*str = 'w';
    printf("buf=%s\n", buf);

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{

    char buf[20] = "helloworld";
    char *const str = buf;
    printf("str=%s\n", str);
    *str = 'w';//能修改不能指向
    printf("str=%s\n", str);
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RIpZsWbP-1649660664502)(C:\Users\宁智波带土\AppData\Roaming\Typora\typora-user-images\image-20220411111236229.png)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{

    char buf[20] = "helloworld";
    char *const str = buf;
    printf("str=%s\n", str);
    // *str = 'w';不能直接
    // printf("str=%s\n", str);
    //str = "hellokitty";不能指向
    return 0;
}

第九章 结构体

; //一旦不在adf这个范围就停止输入
printf(“buf=%s\n”, buf);
return 0;
}
buf=ad05Fk


```c
#include <stdio.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[20];
    //匹配%[^k]遇到这个字符则停止输入
    sscanf("ad05Fkl78adf9Faljs", "%[^k ]", buf); //一旦遇到k字符就停止获取
    printf("buf=%s\n", buf);

    sscanf("ad0 5Fkl78adf9Faljs", "%[^k]", buf); //空格也能打印出来,遇到k则停止
    printf("buf=%s\n", buf);
    return 0;
}
buf=ad05F
buf=ad0 5F
sscanf高级用法4
#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{
    char buf[20];
    sscanf("asdf#sdjh@djkd", "%*[^#]%*c%*[^@]%*c%s", buf);
    printf("buf=%s\n", buf);

    return 0;
}
buf=djkd

[外链图片转存中…(img-nm4DC4LE-1649660664501)]

1.实现strlen函数功能

#include <stdio.h>
#pragma warning(disable : 4996)
unsigned int my_strlen(const char *s)
{
    char *p = s;
    while (*p != '\0')
    {
        p++;
    }
    return p - s;
}

int main()
{
    int num;
    num = my_strlen("helloworld");

    printf("num = %d\n", num);
}

2、实现strcpy函数功能

#include <stdio.h>
#pragma warning(disable : 4996)
// strcpy功能的实现
char *my_strcpy(char *dest, const char *src)
{
    char *p1 = dest;
    const char *p2 = src;
    while (*p2 != '\0')
    {
        *p1 = *p2;
        p1++;
        p2++;
    }
    *p1 = '\0';
    return dest;
}

int main()
{
    char buf[100];
    // char *bufs;
    /*bufs =*/my_strcpy(buf, "hello world");

    printf("buf=%s\n", buf);
    // printf("buf=%s\n", bufs);

    return 0;
}
#include <stdio.h>
#pragma warning(disable : 4996)
// strcpy功能的实现

int my_atoi(const char *str)
{
    const char *s = str;
    int temp = 0;

    while (*s != '\0')
    {
        temp = temp * 10 + (*s - '0');
        s++;
    }
    return temp;
}
int main()
{
    int num;
    char buf[100] = "123456789";
    printf("buf=%s\n", buf);
    num = my_atoi(buf);
    printf("num =%d\n", num);
    return 0;
}
buf=123456789
num =123456789

4、使用sscanf读取"[ti:简单爱]" ":“号与”]"之间的内容


#include <stdio.h>
#pragma warning(disable : 4996)
// strcpy功能的实现

int main()
{
    char buf[100] = "[ti:简单爱]";
    char buf1[100];
    sscanf(buf, "%*[^:]%*c%[^]]", buf1);
    printf("buf1=%s\n", buf1);
}
buf1=简单爱

5、使用 sscanf读取"[02:06:85]" 02(代表分钟) 06(代表秒) 到整型变量min 、 sec 中

#include <stdio.h>
#pragma warning(disable : 4996)
// strcpy功能的实现

int main()
{
    int min, sec;
    sscanf("[02:06.85]", "[%2d:%2d", &min, &sec);
    printf("&min=%02d\n", min); // 02d  打印前两位  没有则用0填充
    printf("&min=%02d\n", sec);
}
&min=02
&min=06

[外链图片转存中…(img-1e4qXAoa-1649660664501)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
// strcpy功能的实现

int main()
{
    char *str = "helloworldhelloworldhelloworldhelloworld";
    int num = 0;
    char *p;
    char *q = str;
    while ((p = strchr(q, 'w')) != NULL)
    {
        num++;
        printf("第%d个w的位置:%d\n", num, p - str); //因为str一直指向元素的开始,所以p-str
        q = p + 1;                                  // p+1是找到的p 元素的下一个位置
    }
    printf("总共找到%d个w\n", num);
    return num;
}1个w的位置:52个w的位置:153个w的位置:254个w的位置:35
总共找到4个w

8.11 const:

[外链图片转存中…(img-7Pv78gfZ-1649660664502)]

[外链图片转存中…(img-BVFirm1O-1649660664502)]

char buf[20] = "helloworld";
    const char *str = buf;
    strcpy(str, "hello kitty!");//能指向不能直接修改
    //*str = 'w';
    printf("buf=%s\n", buf);

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{

    char buf[20] = "helloworld";
    char *const str = buf;
    printf("str=%s\n", str);
    *str = 'w';//能修改不能指向
    printf("str=%s\n", str);
    return 0;
}

[外链图片转存中…(img-RIpZsWbP-1649660664502)]

#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
int main()
{

    char buf[20] = "helloworld";
    char *const str = buf;
    printf("str=%s\n", str);
    // *str = 'w';不能直接
    // printf("str=%s\n", str);
    //str = "hellokitty";不能指向
    return 0;
}

第九章 结构体

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值