嵌入式课程笔记_02_STDC02_20190308

02_STDC02

day1: 二重循环 、 while循环和do循环 、 缓冲区

STDC02_day01_01-break和continue02.ts

无法预知的数字叫随机数
rand标准函数可以用来获得随机数
为了使用这个标准函数需要包含stdlib.h头文件

/CSD1702/biaoc/day06 01rand.c

/*
	随机数演示
*/
#include <stdio.h>
#include <stdlib.h>
int main(){
    printf("%d\n",rand());
    printf("%d\n",rand());
    printf("%d\n",rand());
    return 0;
}
结果:			//伪随机数执行任何次数结果一样
1804289383
846930886
1681692777

srand标准函数用来设置随机数种子
这个标准函数可以把一个整数作为种子使用
不同的种子产生的随机数不同
为了使用这个标准函数也需要包含stdlib.h头文件

/CSD1702/biaoc/day06 01rand.c

/*
	随机数演示
*/
#include <stdio.h>
#include <stdlib.h>
int main(){
    srand(10); //设置随机数种子可以产生新的随机数序列	相同的种子产生相同的序列
    printf("%d\n",rand());
    printf("%d\n",rand());
    printf("%d\n",rand());
    return 0;
}
结果:		
1215069295
1311962008
1086128678

/CSD1702/biaoc/day06 01rand.c

/*
	随机数演示
*/
#include <stdio.h>
#include <stdlib.h>
int main(){
    srand(10); //设置随机数种子可以产生新的随机数序列	相同的种子产生相同的序列
    printf("%d\n",rand());
    srand(10);	//重复使用随机数种子产生的随机数相同
    printf("%d\n",rand());
    srand(10);
    printf("%d\n",rand());
    return 0;
}
结果:		
1215069295
1215069295
1215069295

程序里只需要设置一次随机数种子

time标准函数可以获得当前时间
这个函数用一个整数表示获得的当前时间
同一秒之内获得的代表时间的整数是同一个
为了使用这个标准函数需要包含time.h头文件

/*
	随机数演示
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h> 
int main(){
    srand(time(0));	//time函数调用语句
    printf("%d\n",rand());
    printf("%d\n",rand());
    printf("%d\n",rand());
    return 0;
}
结果:	
每次执行得到不同的三个数字,如:
1302004718
1941879639
1900597542

练习:
编写猜数游戏
计算机里首先产生一个0到99之间的随机数,然后让用户猜
每猜一次要给出相应提示
直到猜对游戏结束

/CSD1702/biaoc/day06 02guess.c

/*
	猜数游戏
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
    int num = 0,guess = 0;
    srand(time(0));
    num = rand() % 100;
    for(;;){
        printf("请猜一个数字:");
        scanf("%d",&guess);
        if (num > guess){
            printf("猜小了\n");
        }
        else if (num < guess){
            printf("猜大了\n");
        }
        else {
            printf("猜对了\n");
            break;
        }
    }
    return 0;
}

STDC02_day01_02-二重循环01.ts

分支和循环都是流程控制语句,它们都可以让程序中的语句不再从上到下执行

goto语句也是流程控制语句
它可以把任何一条语句指定成下一条语句
一般不要使用goto语句

如果一个问题需要使用多组数字的变化过程描述,不同数字的变化频率不同。这个时候就可以采用多重循环解决这样的问题。

54321
5432
543
54
5

/CSD1702/biaoc/day06 03for.c

/*
	多重循环演示
*/
#include <stdio.h>
int main(){
    int num = 0,num1 = 0;
    for (num = 1;num <= 5;num++){
        for (num1 = 5;num1 >= num;num1--){
            printf("%d",num1);
        }
    	printf("\n");
    }
    return 0;
}

编写多重循环的时候外层循环的循环变量代表变化较慢的数字,内层循环的循环变量代表变化较快的数字

练习:
假设一种货币包含三种面值,分别是1元,2元和5元
要求编写程序找到这种货币组成10元的可能性

STDC02_day01_03-二重循环02.ts

/CSD1702/biaoc/day06 04for.c

/*
	多重循环练习
*/
#include <stdio.h>
int main(){
    int num = 0,num1 = 0;
    for (num = 0;num <= 2;num++){
        for(num1 =0;num1 <= 5;num1++){
            if (5 * num + 2 * num1 <= 10){
                printf("5元钱有%d张,2元钱有%d张,1元钱有%d张\n",num,num1,10 - 5 * num - 2 * num1);
            }
        }
    }
}
结果:
5元钱有0张,2元钱有0张,1元钱有105元钱有0张,2元钱有1张,1元钱有85元钱有0张,2元钱有2张,1元钱有65元钱有0张,2元钱有3张,1元钱有45元钱有0张,2元钱有4张,1元钱有25元钱有0张,2元钱有5张,1元钱有05元钱有1张,2元钱有0张,1元钱有55元钱有1张,2元钱有1张,1元钱有35元钱有1张,2元钱有2张,1元钱有15元钱有2张,2元钱有0张,1元钱有0

STDC02_day01_04-while循环和do循环01.ts

while关键字也可以用来编写循环
while循环适合解决事先不知道次数的循环
while循环的格式如下

while(逻辑表达式){
	反复执行的语句
}

反复执行大括号里面的语句直到逻辑表达式结果为假
/CSD1702/biaoc/day06 05while.c

/*
	while循环演示
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
    int num = 0, guess = 0;
    srand(time(0));
    num = rand() % 100;
    while(num != guess){
        printf("请猜一个数字:");
        scanf("%d",&guess);
        if(num > guess){
            printf("猜小了\n")}
        else if(num < guess){
            printf("猜大了\n")}
        else {
            printf("猜对了\n")}
    }
}

把逻辑表达式写成1就成为死循环

while循环里也可以使用break;continue;语句

while循环会交替执行逻辑表达式和大括号里面的语句
while循环第一步计算逻辑表达式
while循环有可能不执行大括号里面的语句

STDC02_day01_05-while循环和do循环02.ts

/CSD1702/biaoc/day06 05while.c

/*
	while循环演示
*/
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
int main(){
    int num = 0, guess = 0;
    srand(time(0));
    //num = rand() % 100;
    while(num != guess){
        printf("请猜一个数字:");
        scanf("%d",&guess);
        if(num > guess){
            printf("猜小了\n")}
        else if(num < guess){
            printf("猜大了\n")}
        else {
            printf("猜对了\n")}
    }
}

直接结束
while循环先执行逻辑表达式判断

do...while也可以用来实现循环
while循环大括号前面的内容挪到大括号后面,然后在大括号前面保留一个do关键字就成为do...while循环
do...while循环的小括号后面必须用分号结束
do...while循环也是交替执行大括号里面的语句和逻辑表达式
do...while循环首先执行大括号里面的语句
do...while循环可以保证把大括号里面的语句至少执行一次

/CSD1702/biaoc/day06 05while.c

/*
	while循环演示
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
    int num = 0, guess = 0;
    srand(time(0));
    num = rand() % 100;
    /*while(num != guess){
        printf("请猜一个数字:");
        scanf("%d",&guess);
        if(num > guess){
            printf("猜小了\n");
        }
        else if(num < guess){
            printf("猜大了\n");
        }
        else {
            printf("猜对了\n");
        }
    }*/
    do{
        printf("请输入一个数字:");
        scanf("%d",&guess);
        if (num > guess){
            printf("猜小了\n");
        }
        else if (num < guess){
            printf("猜大了\n");
        }
        else {
            printf("猜对了\n");
        }
    }while (num !=guess);     //do...while后边有分号
}

STDC02_day01_06-缓冲区01.ts

缓冲区用来临时存放数字
scanf标准函数工作的时候用到了输入缓冲区
用户在键盘上输入的数字首先进入输入缓冲区然后才会被程序得到
先进入输入缓冲区的数据必须首先处理
如果用户输入的数据格式和程序中需要的格式不一致就导致后面的数据得不到处理

/CSD1702/biaoc/day06 06inbuf.c

/*
	输入缓冲区演示
*/
#include <stdio.h>
int main(){
    int num = 0, num1 = 0;
    printf("请输入一个数字:");
    scanf("%d",&num);
    printf("num是%d\n",num);
    printf("请输入一个数字:");
    scanf("%d",&num1);
    printf("num是%d\n",num1);    
    return 0;  
}
结果:
请输入一个数字:23
num是23
请输入一个数字:76
num是76

请输入一个数字:34.8  //程序中要整数,不能处理小数,输入处理不了的数,后边也不能处理
num是34
请输入一个数字:num是0

使用如下两条语句可以把输入缓冲区里第一个换行字符和它前面的所有字符都丢掉

scanf("%*[^\n]");
scanf("%*c");

/CSD1702/biaoc/day06 06inbuf.c

/*
	输入缓冲区演示
*/
#include <stdio.h>
int main(){
    int num = 0, num1 = 0;
    printf("请输入一个数字:");
    scanf("%d",&num);
    scanf("%*[^\n]");    //添加两条语句
	scanf("%*c");
    printf("num是%d\n",num);
    printf("请输入一个数字:");
    scanf("%d",&num1);
    printf("num是%d\n",num1);    
    return 0;  
}
结果:
请输入一个数字:34.7
num是34
请输入一个数字:23
num是23

STDC02_day01_07-缓冲区02.ts

printf函数在工作的时候使用了输出缓冲区

/CSD1702/biaoc/day06 07outbuf.c

/*
	输入缓冲区演示
*/
#include <stdio.h>
int main(){
	printf("1");	//添加了\n就会显示1了
    while(1){        
    }
    return 0;  
}
结果:

输出缓冲区里的内容只有在以下四种情况下才会显示在屏幕上
​ 1.输出缓冲区里换行字符前面的内容会显示在屏幕上

/CSD1702/biaoc/day06 07outbuf.c

/*
	输入缓冲区演示
*/
#include <stdio.h>
int main(){
	printf("1\n");	//添加了\n就会显示1了
    while(1){        
    }
    return 0;  
}
结果:
1

​ 2.当程序结束的时候程序放在输出缓冲区里的内容也会显示在屏幕上

/CSD1702/biaoc/day06 07outbuf.c

/*
	输入缓冲区演示
*/
#include <stdio.h>
int main(){
	printf("1");	//程序结束,显示输出缓冲区内容
    /*while(1){        
    }*/
    return 0;  
}
结果:
1

​ 3.当输出缓冲区被充满的时候里面的内容会显示在屏幕上

/CSD1702/biaoc/day06 07outbuf.c

/*
	输入缓冲区演示
*/
#include <stdio.h>
int main(){	
    while(1){  
    	printf("1");
    }
    return 0;  
}
结果:
(输出缓冲区充满后会连续打印1)

​ 4.使用fflush(stdout)语句可以把输出缓冲区里的内容强制显示在屏幕上

/CSD1702/biaoc/day06 07outbuf.c

/*
	输入缓冲区演示
*/
#include <stdio.h>
int main(){
	printf("1");
    fflush(stdout);
    while(1){        
    }
    return 0;  
}
结果:
1

STDC02_day01_08-一维数组01.ts

数组可以用来代表内存里一组连续的同类型存储区
这些存储区叫做数组的元素
声明数组的时候除了提供类型名称和数组名称以外还需要提供一个整数用来表示数组里的存储区个数

/CSD1702/biaoc/day06 08arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5];	//数组声明    
    return 0;
}

数组一旦存在它里面包含的存储区个数就不可以改变
数组通常不会作为整体使用,一般一次只使用其中的某个存储区
数组里每个存储区有一个编号,不同存储区编号不同。这个编号叫做数组的下标
第一个存储区的下标是0,向后依次递增
有效下标范围从0开始到存储区个数减一位置,超过范围的下标不能使用
数组名称和下标结合就可以表示下标对应的存储区
/CSD1702/biaoc/day06 08arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5];	//数组声明
    arr[2] = 10;
	printf("arr[2]是%d\n",arr[2]);
	return 0;
}
结果:
arr[2]是10

STDC02_day01_09-一维数组02.ts

可以在一个for循环里依次处理数组中的每个存储区
for循环的循环变量代表数组中所有存储区的下标

/CSD1702/biaoc/day06 08arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5];	//数组声明
    int num = 0;
    /*arr[2] = 10;
	printf("arr[2]是%d\n",arr[2]);*/
    for (num = 0;num <= 4;num++){
        arr[num] = num;
    }
	return 0;
}

练习:
编写程序,把数组存储区内容从大到小打印输出

/CSD1702/biaoc/day06 08arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5];	//数组声明
    int num = 0;
    /*arr[2] = 10;
	printf("arr[2]是%d\n",arr[2]);*/
    for (num = 0;num <= 4;num++){
        arr[num] = num;
    }
    for (num = 4;num >= 0;num--){
        printf("%d ",arr[num]);
    }
    printf("\n");
	return 0;
}
结果:
4 3 2 1 0 

数组也应该初始化
初始化数组的时候需要提供多个初始化数据,这些初始化数据应该写在一对大括号中间,相邻数据之间用逗号分开

/CSD1702/biaoc/day06 08arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5] = {0,1,2,3,4};	//数组初始化
    int num = 0;
    /*arr[2] = 10;
	printf("arr[2]是%d\n",arr[2]);*/
    /*for (num = 0;num <= 4;num++){
        arr[num] = num;
    }*/
    for (num = 4;num >= 0;num--){
        printf("%d ",arr[num]);
    }
    printf("\n");
	return 0;
}
结果:
4 3 2 1 0 

如果初始化数据个数超过存储区个数就把多余的数据忽略

/CSD1702/biaoc/day06 08arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5] = {0,1,2,3,4,5,6};	//数组初始化
    int num = 0;
    /*arr[2] = 10;
	printf("arr[2]是%d\n",arr[2]);*/
    /*for (num = 0;num <= 4;num++){
        arr[num] = num;
    }*/
    for (num = 4;num >= 0;num--){
        printf("%d ",arr[num]);
    }
    printf("\n");
	return 0;
}
结果:
4 3 2 1 0 

如果初始化数据个数比存储区个数少就把后面的存储区自动初始化成0

/CSD1702/biaoc/day06 08arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5] = {0,1,2};	//数组初始化
    int num = 0;
    /*arr[2] = 10;
	printf("arr[2]是%d\n",arr[2]);*/
    /*for (num = 0;num <= 4;num++){
        arr[num] = num;
    }*/
    for (num = 4;num >= 0;num--){
        printf("%d ",arr[num]);
    }
    printf("\n");
	return 0;
}
结果:
0 0 2 1 0 

如果初始化数据个数和存储区个数一样就可以省略数组声明里的存储区个数

/CSD1702/biaoc/day06 08arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[] = {0,1,2,3,4};	//初始化数据个数和存储区个数一样
    int num = 0;
    /*arr[2] = 10;
	printf("arr[2]是%d\n",arr[2]);*/
    /*for (num = 0;num <= 4;num++){
        arr[num] = num;
    }*/
    for (num = 4;num >= 0;num--){
        printf("%d ",arr[num]);
    }
    printf("\n");
	return 0;
}

结果:
4 3 2 1 0

STDC02_day01_10-一维数组03.ts

练习:
编写程序从键盘得到一个非负整数,统计这个数字里每个个位数出现的次数并把结果显示在平面上
​ 3462321
1出现了1次
2出现了2次
3出现了2次
4出现了1次
6出现了1次

/CSD1702/biaoc/day06 09arr.c

/*
	数组练习
*/
#include <stdio.h>
int main(){
    int arr[10] = {0},num = 0;	//下标为n的存储区记录下标出现的次数
    printf("请输入一个数字:");
    scanf("%d"&num);
    do {		
        arr[num % 10]++;//先对10取余作为下标,该存储区数字加1表示增加1次
        num /= 10;//将最右边一位去掉
    }while (num);
    for (num = 0;num <= 9;num++){
        if (arr[num]){//arr[num]为0表示该数字在输入的数中没有出现,不显示
            printf("数字%d出现%d次\n",num,arr[num]);
        }
    }
	return 0;
}
结果:
请输入一个数字:234351234
数字1出现1次
数字2出现2次
数字3出现3次
数字4出现2次
数字5出现1次

预习:
​ 1.数组
​ 2.变长数组
​ 3.多维数组

day2: 一维数组02 、 可变长数组 、 多维数组

STDC02_day02_01-一维数组04.ts

练习:
编写程序产生一张彩票,彩票里包含7个1到36之间的随机数
产生之后把彩票里的数字显示在屏幕上
允许彩票里出现重复数字

/CSD1702/biaoc/day07 01lottery.c

/*
	彩票练习
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
    int arr[7] = {0},num = 0;
    srand(time(0));
    for (num = 0;num <= 6;num++){
        arr[num] = rand() % 36 + 1;
    }
    for (num = 0;num <= 6;num++){
        printf("%d ",arr[num]);
    }
    printf("\n");
    return 0;
}
结果:
会生成7位1到36的彩票数字,但是可能会出现重复数字

STDC02_day02_02-一维数组05.ts

/CSD1702/biaoc/day07 01lottery.c

/*
	彩票练习
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
    int arr[7] = {0},num = 0,tmp = 0,size = 0;//arr存放彩票数字 num循环变量 tmp用于临时存数 size记录已经得到多少有效数字
    srand(time(0));
    /*for (num = 0;num <= 6;num++){
        arr[num] = rand() % 36 + 1;
    }*/
    do{
        //获得一个新数字
        tmp = rand() % 36 + 1;	
        //用新数字和以前得到的所有有效数字依次做对比
        for(num = 0;num <= size - 1;num++){
            if(arr[num] == tmp){
                //如果新数字和以前的某个数字一样就说明新数字不能用
                break;
            }
        }
        if(num == size){	
            //如果前面的循环是正常结束的,就说明新数字可以使用,应该把它放到数组里,另外还需要把已经得到的数字个数加一
            arr[size] = tmp;
            size++;
        }
    }while(size < 7);
    for (num = 0;num <= 6;num++){
        printf("%d ",arr[num]);
    }
    printf("\n");
    return 0;
}
结果:
生成7个不相同的彩票数字

在程序中加入兑奖功能
输入7个随机数跟这个彩票数字进行比较,输出正确几个数

STDC02_day02_03-一维数组06.ts

/CSD1702/biaoc/day07 01lottery.c

/*
	彩票练习
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
    int arr[7] = {0},arr1[7] = {0},num = 0,num1 = 0,tmp = 0,size = 0,cnt = 0;//arr存放彩票数字 arr1存放用户输入的数字 num,num1循环变量 tmp用于临时存数 size记录已经得到多少有效数字 cnt计算相同号码的个数
    srand(time(0));
    /*for (num = 0;num <= 6;num++){
        arr[num] = rand() % 36 + 1;
    }*/
    do{
        //获得一个新数字
        tmp = rand() % 36 + 1;	
        //用新数字和以前得到的所有有效数字依次做对比
        for(num = 0;num <= size - 1;num++){
            if(arr[num] == tmp){
                //如果新数字和以前的某个数字一样就说明新数字不能用
                break;
            }
        }
        if(num == size){	
            //如果前面的循环是正常结束的,就说明新数字可以使用,应该把它放到数组里,另外还需要把已经得到的数字个数加一
            arr[size] = tmp;
            size++;
        }
    }while(size < 7);
    for (num = 0;num <= 6;num++){
        printf("%d ",arr[num]);
    }
    printf("\n");
    for(num = 0;num <= 6;num++){
        printf("请输入一个数字:");
        scanf("%d",&arr1[num]);
    }
    cnt = 0;          //计算买对的个数
    for(num = 0;num <= 6;num++){
        for(num1 =0;num1 <= 6;num1++){
            if(arr[num] == arr1[num1]){
                cnt++;
                break;
            }
        }
    }
    printf("买对的数字个数是%d\n",cnt);
    return 0;
}

STDC02_day02_04-可变长数组01.ts

数组名称不可以代表存储区
数组名称代表数组里第一个存储区的地址

/CSD1702/biaoc/day07 02arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5] = {0};
    printf("%p %p\n",arr,&arr[0]);
    return 0;
}
输出:
0x7fff8abce0d0 0x7fff8abce0d0

可以对数组名称进行sizeof计算,结果是整个数组包含的总字节个数

/CSD1702/biaoc/day07 02arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5] = {0};
    printf("%p %p\n",arr,&arr[0]);
    printf("sizeof(arr)是%d\n",sizeof(arr));
    return 0;
}
输出:
0x7fffe66a0b60 0x7fffe66a0b60
sizeof(arr)是20

C99规范里允许声明数组的时候使用变量表示数组里的存储区个数
这种数组叫变长数组

/CSD1702/biaoc/day07 02arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5] = {0},size = 0;
    printf("%p %p\n",arr,&arr[0]);
    printf("sizeof(arr)是%d\n",sizeof(arr));
    printf("请输入一个整数:");
    scanf("%d",&size);
    int arr1[size];	//变长数组
    printf("sizeof(arr1)是%d\n",sizeof(arr1));
    return 0;
}
输出:
0x7fffe66a0b60 0x7fffe66a0b60
sizeof(arr)是20
请输入一个整数:3
sizeof(arr1)是12

gcc -std=c99 02arr.c
./a.out

每次程序运行过程中数组里存储区个数不会改变
如果程序多次运行则每次运行的时候数组里的存储区个数可以不同

STDC02_day02_05-可变长数组02.ts

变长数组不能初始化

/CSD1702/biaoc/day07 02arr.c

/*
	数组演示
*/
#include <stdio.h>
int main(){
    int arr[5] = {0},size = 0;
    printf("%p %p\n",arr,&arr[0]);
    printf("sizeof(arr)是%d\n",sizeof(arr));
    printf("请输入一个整数:");
    scanf("%d",&size);
    int arr1[size] = {1,2,3};	//变长数组 变长数组不能初始化
    printf("sizeof(zrr1)是%d\n",sizeof(arr1));
    return 0;
}
输出:
错误

练习:
编写程序产生一张彩票,彩票里包含多个1到36之间的随机数,数组个数由用户临时决定
产生之后把彩票里的数字显示在屏幕上
允许彩票里出现重复数字

/CSD1702/biaoc/day07 03arr.c

/*
	变长数组练习
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
    int size = 0,num = 0;
    srand(time(0));
    printf("请输入数字个数:");
    scanf("%d",&size);
    int arr[size];  
    for (num = 0;num <= size - 1;num++){
        arr[num] = rand() % 36 + 1;
    }
    for (num = 0;num <= size - 1;num++){
        printf("%d ",arr[num]);
    }
    printf("\n");
    return 0;
}
结果:
请输入数字个数:5
27 26 11 33 6

STDC02_day02_06-多维数组01.ts

不能描述存储区分组情况的数组叫一维数组
多维数组可以描述存储区的分组情况
最常见的多维数组是二维数组,二维数组只能表示存储区的一次分组情况
声明二维数组的时候需要提供两个整数,前一个整数表示分组个数,后一个整数表示每个分组里的存储区个数

/CSD1702/biaoc/day07 04arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[3][2];	//二维数组声明
    arr[1][0] = 10;
    return 0;
}

表示二维数组中某个存储区的时候需要使用两个下标,前一个下标表示分组编号(组下标),后一个下标表示存储区编号(组内下标
组下标的有效范围从0开始到分组个数减一为止
组内下标的有效范围从0开始到组内存储区个数减一为止

STDC02_day02_07-多维数组02.ts

/CSD1702/biaoc/day07 04arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[3][2];	//二维数组声明
    int row = 0,col = 0,cnt = 1;
    //arr[1][0] = 10;
    for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	arr[row][col] = cnt;
            cnt++;
        }
    }
    for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	printf("%d ",arr[row][col]);
        }
    printf("\n");
    }
    return 0;
}
输出:
1 2
3 4
5 6

可以采用双重循环依次处理二维数组里的每个存储区
可以把二维数组当作一维数组进行初始化

/CSD1702/biaoc/day07 04arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[3][2] = {1,2,3,4,5,6};	//二维数组声明
    int row = 0,col = 0,cnt = 1;
    //arr[1][0] = 10;
    /*for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	arr[row][col] = cnt;
            cnt++;
        }
    }*/
    for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	printf("%d ",arr[row][col]);
        }
    printf("\n");
    }    
    return 0;
}
输出:
1 2
3 4
5 6

二维数组初始化条件和一维数组初始化相似,没有初始化的为0

/CSD1702/biaoc/day07 04arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[3][2] = {1,2,3,4};	//二维数组声明
    int row = 0,col = 0,cnt = 1;
    //arr[1][0] = 10;
    /*for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	arr[row][col] = cnt;
            cnt++;
        }
    }*/
    for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	printf("%d ",arr[row][col]);
        }
    printf("\n");
    }    
    return 0;
}
输出:
1 2
3 4
0 0

可以对初始化数据进行分组,每组数据用来初始化一组存储区

/CSD1702/biaoc/day07 04arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[3][2] = {{1,2},{3,4},{5,6}};	//二维数组声明
    int row = 0,col = 0,cnt = 1;
    //arr[1][0] = 10;
    /*for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	arr[row][col] = cnt;
            cnt++;
        }
    }*/
    for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	printf("%d ",arr[row][col]);
        }
    printf("\n");
    }    
    return 0;
}

输出:
1 2
3 4
5 6

没有初始化的数组值默认为0

/CSD1702/biaoc/day07 04arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[3][2] = {{1,2},{3},{5,6}};	//二维数组声明
    int row = 0,col = 0,cnt = 1;
    //arr[1][0] = 10;
    /*for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	arr[row][col] = cnt;
            cnt++;
        }
    }*/
    for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	printf("%d ",arr[row][col]);
        }
    printf("\n");
    }    
    return 0;
}
输出:
1 2
3 0
5 6

如果可以根据初始化数据计算出分组个数就可以省略数组声明里的分组个数

/CSD1702/biaoc/day07 04arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[][2] = {{1,2},{3},{5,6}};	//二维数组声明
    int row = 0,col = 0,cnt = 1;
    //arr[1][0] = 10;
    /*for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	arr[row][col] = cnt;
            cnt++;
        }
    }*/
    for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	printf("%d ",arr[row][col]);
        }
    printf("\n");
    }    
    return 0;
}
输出:
1 2
3 0
5 6

/CSD1702/biaoc/day07 04arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[][2] = {1,2,3,5,6};	//二维数组声明
    int row = 0,col = 0,cnt = 1;
    //arr[1][0] = 10;
    /*for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	arr[row][col] = cnt;
            cnt++;
        }
    }*/
    for(row = 0;row <= 2;row++){
        for(col = 0;col <= 1;col++){
        	printf("%d ",arr[row][col]);
        }
    printf("\n");
    }
    return 0;
}
输出:
1 2
3 5
6 0

STDC02_day02_08-多维数组03.ts

二维数组名称也可以用来代表第一个存储区的地址

/CSD1702/biaoc/day07 05arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[3][2] = {0};
	printf("arr是%p,&arr[0][0]是%p\n",arr,&arr[0][0]);
}
输出:
arr是000000000062FE30,&arr[0][0]000000000062FE30

对二位数组名称进行sizeof计算的结果是二维数组的所有存储区包含的总字节个数

/CSD1702/biaoc/day07 05arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[3][2] = {0};
	printf("arr是%p,&arr[0][0]是%p\n",arr,&arr[0][0]);
    printf("sizeof(arr)是%d\n",sizeof(arr));
}
输出:
arr是000000000062FE30,&arr[0][0]000000000062FE30
sizeof(arr)24

二位数组名称也可以和一个下标配合使用,这个写法表示下标对应组中第一个存储区的地址
这个写法也可以看作一维数组名称,这个一维数组里包含下标代表的组里所有的存储区

/CSD1702/biaoc/day07 05arr.c

/*
	二维数组演示
*/
#include <stdio.h>
int main(){
    int arr[3][2] = {0};
	printf("arr是%p,&arr[0][0]是%p\n",arr,&arr[0][0]);
    printf("sizeof(arr)是%d\n",sizeof(arr));
    printf("arr[1]是%p\n,&arr[1][0]是%p\n",arr[1],&arr[1][0]);
    printf("sizeof(arr[1])是%d\n",sizeof(arr[1]));
}
输出:
arr是0x7fff70fb0cf0,&arr[0][0]是0x7fff70fb0cf0
sizeof(arr)是24
arr[1]是0x7fff70fb0cf8,&arr[1][0]是0x7fff70fb0cf8
sizeof(arr[1])是8

STDC02_day02_09-多维数组04.ts

练习:
11112
40002
40002
40002
43333
把以上25个数字填充到一个二维数组里,然后再按照这个格式显示再屏幕上,只有0可以用初始化的方法填到二维数据里

/CSD1702/biaoc/day07 06arr.c

/*
	二维数组练习
*/
#include <stdio.h>
int main(){
	int arr[5][5] = {0};
	int row = 0,col = 0;
    for(row = 0;row <= 4;row++){
        for(col = 0;col <= 4;col++){
            if(!row && col <= 3){
                arr[row][col] = 1;
            }
            else if(row <= 3 && col == 4){
                arr[row][col] = 2;
            }
            else if(row == 4 && col >=1){
                arr[row][col] = 3;
            }
            else if(row >= 1 && !col){
                arr[row][col] = 4;
            }
        }
    }
    for(row = 0;row <=4;row++){
        for(col = 0;col <= 4;col++){
            printf("%d",arr[row][col]);
        }
        printf("\n");
    }
    return 0;
}
结果:
11112
40002
40002
40002
43333

还可以按照四个1,四个2,四个3,四个4的顺序输入

预习:
​ 1.函数

day3: 多维数组02 、 函数01

STDC02_day03_01-多维数组05.ts

显示模拟扫雷,10个O,90个X

XXXXXXXXXX
XXXOOXXXXX
XXXXXXXXXX
XXOOXXXXXX
XXXXXXXXXX
XXXOOXXXXX
XXXXXXXXXX
XXOOXXXXXX
XXXOOXXXXX
XXXXXXXXXX

/CSD1702/biaoc/day08 01mine.c

/*
	扫雷练习
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
	int arr[10][10] = {0};
    int row = 0, col = 0,cnt = 0;
	srand(time(0));
    do {
        row = rand() % 10;
        col = rand() % 10;
        if (!arr[row][col]){
            arr[row][col] = -1;
            cnt++;
        }
    } while(cnt < 10);
    for(row = 0;row <= 9;row++){
        for(col = 0;col <=9;col++){
            if(!arr[row][col]){
                printf("X");
            }
            else if(arr[row][col] == -1){
                printf("O");
            }
        }
        printf("\n");
    }
    return 0;
}
结果:
XXXXXXXXXX
XXXXXXXXXX
XOXXXXXXXX
XXOXXOXOXO
OXXXOXXXXX
XXXXXXXXXX
OXXXXXXXXX
XXXXXXXXOX
XXXXXXXXXX
XXOXXXXXXX

STDC02_day03_02-多维数组06.ts

/CSD1702/biaoc/day08 01mine.c

/*
	扫雷练习
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
	int arr[10][10] = {0};
    int delta[][2] = {-1,-1,-1,0,-1,1,0,-1,0,1,1,-1,1,0,1,1};
    int row = 0, col = 0,cnt = 0,num = 0;
	srand(time(0));
    do{
        row = rand() % 10;
        col = rand() % 10;
        if (!arr[row][col]){
            arr[row][col] = -1;
            cnt++;
        }
    }while(cnt < 10);
    for(row = 0;row <= 9;row++){
        for(col = 0;col <=9;col++){
            if (arr[row][col] != -1){    //把不是地雷的排除掉
                continue;
            }
            for(num = 0;num <= 7;num++){
                int tmp_row = row + delta[num][0];
                int tmp_col = col + delta[num][1]; 
                if (tmp_row < 0 || tmp_row > 9){
                    continue;
            	}
            	if (tmp_col < 0 || tmp_col > 9){
                	continue;
            	}
          		if (arr[tmp_row][tmp_col] == -1){
                	continue;
            	}
            	arr[tmp_row][tmp_col]++;
            } 
        }
    }
    for(row = 0;row <= 9;row++){
        for(col = 0;col <=9;col++){
            if(!arr[row][col]){
                printf("O");	//改为用O表示空位置
            }
            else if(arr[row][col] == -1){
                printf("X");	//改为用X表示地雷
            }
            else {
                printf("%d",arr[row][col]);
            }
        }
        printf("\n");
    }
    return 0;
}
结果:
OO1X211OOO
OO112X1OOO
11OO111OOO
X211OOOOOO
12X1111O11
O1111X1O2X
O111111O3X
O1X1OOOO2X
O111OOO122
OOOOOOO1X1

row col
row - 1, col - 1 -1,-1
row - 1, col -1,0
row - 1, col + 1 -1,1
row, col - 1 0,-1
row, col + 1 0,1
row + 1, col - 1 1,-1
row + 1, col 1,0
row + 1, col + 1 1,1

STDC02_day03_03-函数01.ts

C语言里可以采用分组方式管理语句
我们把每个分组叫做一个函数

多函数程序执行时需要对时间进行划分,时间划分需要遵守如下规则
​ 1.整个程序的执行时间被分成几段,不同时间段被分配给不同的函数使用
​ 2.所有时间段之间不能重叠并且必须连续
​ 3.如果函数A在执行过程中把一段时间分配给函数B使用,则函数B在完成所有工作之后必须把后面的时间还给函数A

func2               ****    
func1           ****    *****
main 	********             ************
****表示每个函数执行时间

如果函数A在执行过程中把自己的时间分配给函数B使用就表示他们之间存在函数调用关系
在这个关系里函数A叫做调用函数,函数B叫做被调用函数
在被调用函数工作的时间范围内函数调用关系才存在
调用函数里编写函数调用语句可以产生函数调用关系

STDC02_day03_04-函数02.ts

/CSD1702/biaoc/day08 02func.c

/*
	函数演示
*/
#include <stdio.h>
void func(void){
    printf("1\n");
}
int main(){
    func();
    return 0;
}
输出:
1

不可以跨函数使用变量

/CSD1702/biaoc/day08 02func.c

/*
	函数演示
*/
#include <stdio.h>
void func(void){
    int num = 10;
    printf("1\n");
}
int main(){
    func();
    printf("num是%d\n",num);    //num是函数func定义的,main函数不能使用
    return 0;
}
结果:
编译不能通过

不同函数里的变量可以重名

/CSD1702/biaoc/day08 02func.c

/*
	函数演示
*/
#include <stdio.h>
void func(void){
    int num = 10;
    printf("1\n");
}
int main(){
    int num = 100;
    func();
    printf("num是%d\n",num);
    return 0;
}
结果:
num = 100

如果一个函数多次执行,则每次执行的时候,它里面的变量代表的存储区都可能不同

/CSD1702/biaoc/day08 02func.c

/*
	函数演示
*/
#include <stdio.h>
void func(void){
    int num;
    printf("num是%d\n",num);
    num = 10;
}
void func1(void){
    int val = 100;
    func();
}
int main(){
    func();
    func1();
    return 0;
}
视频结果:
num是-1218379211
num是134513662

/CSD1702/biaoc/day08 02func.c

/*
	函数演示
*/
#include <stdio.h>
void func(void){
    int num;
    printf("num是%d\n",num);
    num = 10;
}
void func1(void){
    int val = 100;
    func();
}
int main(){
    func();
    func();
    func1();
    return 0;
}
视频结果:
num是-1218379211
num是10   
num是134513662

声明变量的时候可以使用volatile关键字,使用这个关键字声明的变量可以被其他程序修改

STDC02_day03_05-函数03.ts

函数调用过程中通常会伴随着两个函数之间的数据传递
数据传递存在两个完全相反的方向,可以从调用函数向被调用函数传递数据也可以从被调用函数向调用函数传递数据
任何方向的数据传递都使用的被调用函数提供的存储区

只能从被调用函数向调用函数传递一个数据
这个数据叫被调用函数的返回值
只有在被调用函数结束的时候才能传递返回值
被调用函数里使用return关键字指定返回值的数值
被调用函数把返回值记录在一个专门的存储区里,被调用函数需要把这个存储区的类型名称写在函数名称前
调用函数里把函数调用语句当作数字使用就可以得到被调用函数的返回值

/CSD1702/biaoc/day08 03return.c

/*
	返回值演示
*/
#include <stdio.h>
int read(void){
    int num = 0;
    printf("请输入一个数字:");
    scanf("%d",&num);
    return num;
}
int main(){
    int num = read();
    printf("num是%d\n",num);
    return 0;
}
结果:
请输入一个数字:45
num是45

如果被调用函数里没有使用return关键字设置返回值数值则存放返回值的存储区里的内容是随机的
调用函数只有一次获得返回值的机会,得到返回值以后或者立刻使用或者转存到其他存储区

STDC02_day03_06-函数04.ts

如果函数不提供返回值就需要在函数名称前写void,这表示函数不提供用来记录返回值的存储区
如果函数名称前什么都没有,在C89规范里表示函数有一个整数类型的存储区用来存放返回值,在C99规范里不允许这样

被调用函数不可以使用数组记录返回值

练习:
编写函数从键盘得到两个整数,把他们的和作为返回值传递给调用函数

/CSD1702/biaoc/day08 04add.c

/*
	返回值练习
*/
#include <stdio.h>
int add(void){
    int num = 0, num1 = 0;
    printf("请输入两个整数:");
    scanf("%d%d",&num,&num1);
    return num + num1;
}
int main(){
    int num = add();
    printf("求和结果是%d\n",num);
    return 0;
}

输出:
请输入两个整数:3 8
求和结果是11

STDC02_day03_07-函数05.ts

可以从调用函数向被调用函数传递任意多个数据,这些数据的类型也是任意的
被调用函数需要为每个数据提供一个同类型的存储区
在函数名称后面的小括号里写一组变量声明语句,相邻的变量声明语句用逗号分开,这些变量就代表了用来传递数据的那些存储区
这些变量叫做函数的形式参数,小括号里的所有内容叫做函数的形式参数列表。
每个形式参数都必须有自己的类型名称
被调用函数里可以像使用变量一样使用形式参数,每个形式参数代表调用函数传递过来的一个数字

/CSD1702/biaoc/day08 05param.c

/*
	参数演示
*/
#include <stdio.h>
void print(int num,int num1){
    printf("%d %d\n",num,num1);
}
int main(){
    print(3,6);
    return 0;
}
输出:
3 6

函数调用语句的小括号里需要为每个形式参数提供一个对应的数字,这些数字会被传递给被调用函数,这些数字叫做实际参数

/CSD1702/biaoc/day08 05param.c

/*
	参数演示
*/
#include <stdio.h>
void print(int num,int num1){
    printf("%d %d\n",num,num1);
}
int main(){
    print(3,6);
    print(4 + 6, 8 - 3);
    return 0;
}
输出:
3 6
10 5

只要能当作数字使用的内容都可以作为实际参数使用
如果函数不提供形式参数就需要在小括号里写void
如果小括号里什么都没有表示函数可以提供任意多个不同类型的形式参数

练习:
编写函数解决鸡兔同笼问题
从调用函数得到头和脚的数量并把兔子的数量传递给调用函数

自己编写的代码

/*
	鸡兔同笼问题	
*/
#include <stdio.h>
int chookandrabbit(int head,int foot){    
    return (foot - 2 * head)/2;
}
int main(){
    int rabbit = 0;
    rabbit = chookandrabbit(40,100);
    printf("兔子的数量是%d\n",rabbit);
    return 0;
}
结果:
兔子的数量是10

STDC02_day03_08-函数06.ts

/CSD1702/biaoc/day08 06rabbit.c

/*
	鸡兔同笼练习	
*/
#include <stdio.h>
int rabbit(int heads,int legs){
    int num = 0;
    for(num = 0;num <= heads;num++){
        if(4 * num + 2 * (heads - num) == legs){
            return num;
        }
    }
}
int main(){
    int heads = 0,legs = 0,num = 0;
    printf("请输入头和脚的数量:");
    scanf("%d%d",&heads,&legs);    
    num = rabbit(heads,legs);
    printf("兔子一共有%d只,鸡一共有%d只\n",heads,heads - num);
    return 0;
}
结果:
请输入头和脚的数量:40 100
兔子一共有40只,鸡一共有30只

STDC02_day03_09-函数07.ts

练习:
在屏幕上显示
1 X 9 = 9
2 X 8 = 16
3 X 7 = 21
4 X 6 = 24
5 X 5 = 35
每行使用一个函数调用语句显示

/CSD1702/biaoc/day08 06rabbit.c

/*
	函数练习		
*/
#include <stdio.h>
void print(int num,int num1){
    printf("%d X %d = %d\n",num,num1,num * num1);
}
int main(){
    int num = 0;
    for(num = 1;num <= 5;num++){
        print(num,10 - num);
    }
    return 0;
}
结果:
1 X 9 = 9
2 X 8 = 16
3 X 7 = 21
4 X 6 = 24
5 X 5 = 25

预习:
​ 1.函数
​ 2.递归函数
​ 3.作用域和生命周期
​ 4.全局变量和局部变量

day4: 函数02 、 递归和递推 、 变量和作用域

STDC02_day04_01-函数08.ts

数组可以作为形式参数使用

/CSD1702/biaoc/day09 01param.c

/*
	数组形式参数演示
*/
#include <stdio.h>
void print(int arr[5]){
    int num = 0;
    for(num = 0;num <= 4;num++){
        printf("%d ",arr[num]);
    }
    printf("\n");
}
int main(){
    int arr[] = {1,2,3,4,5};
    print(arr);
    return 0;
}
结果:
1 2 3 4 5

数组作为形式参数的时候,真正的形式参数并不是数组,而是一个可以当作数组使用的变量
数组形式参数里包含的所有存储区都不是被调用函数提供的
声明数组形式参数的时候可以省略表示存储区个数的整数

/CSD1702/biaoc/day09 01param.c

/*
	数组形式参数演示
*/
#include <stdio.h>
void print(int arr[],int size){
    int num = 0;
    for(num = 0;num <= size - 1;num++){
        printf("%d ",arr[num]);
    }
    printf("\n");
}
int main(){
    int arr[] = {1,2,3,4,5};
    print(arr,5);
    return 0;
}
结果:
1 2 3 4 5

使用数组形式参数的时候,需要另外提供一个整数类型的形式参数表示数组形式参数里包含的存储区个数

STDC02_day04_02-函数09.ts

通过数组形式参数可以让被调用函数使用其他函数提供的存储区
调用函数可以任意使用数组形式参数里的存储区
数组形式参数可以实现双向数据传递,这种参数叫输入输出参数

/CSD1702/biaoc/day09 02param.c

/*
	数组形式参数演示
*/
#include <stdio.h>
void neg(int arr[],int size){
	int num = 0;
    for(num = 0;num <= size - 1;num++){
    	arr[num] = 0 - arr[num];    //取相反数   
    }
}
int main(){
    int arr[] = {1,2,3,4,5},num = 0;
    neg(arr,5);   //取数组arr的相反数
    for(num = 0;num <= 4;num++){
        printf("%d ",arr[num]);
    }
    printf("\n");
    return 0;
}
结果:
-1 -2 -3 -4 -5

STDC02_day04_03-函数10.ts

C语言里函数参数的个数可以不固定,这种参数叫变长参数
编写函数的时候不能给变长参数命名,所以函数里需要使用特殊的方法得到这些参数的内容(知道即可,很少使用)

被调函数写在主函数上面

/CSD1702/biaoc/day09 03func.c

/*
	数组形式参数演示
*/
#include <stdio.h>
int add(int num,int num1){
	return num + num1;
}
int main(){
    int num = 0,num1 = 0,sum = 0;
	printf("请输入两个数字:");
    scanf("%d%d",&num,&num1);
    sum = add(num,num1);
    printf("sum是%d\n",sum);
    return 0;
}
结果:
请输入两个数字:4 7
sum是11

/CSD1702/biaoc/day09 03func.c

/*
	数组形式参数演示
*/
#include <stdio.h>
int main(){
    int num = 0,num1 = 0,sum = 0;
	printf("请输入两个数字:");
    scanf("%d%d",&num,&num1);
    sum = add(num,num1);
    printf("sum是%d\n",sum);
    return 0;
}
int add(int num,int num1){
	return num + num1;
}
结果:
请输入两个数字:4 7
sum是11
/*
	数组形式参数演示
*/
#include <stdio.h>
int main(){
    int num = 0,num1 = 0,sum = 0;
	printf("请输入两个数字:");
    scanf("%d%d",&num,&num1);
    sum = add(num,num1);
    printf("sum是%d\n",sum);
    return 0;
}
double add(double num,double num1){    //函数的真实格式和隐式声明的格式不同则编译就会出错
	return num + num1;
}
结果:
会出错

如果编译器首先遇到函数调用语句就会猜测函数的格式,编译器认为函数有一个整数类型存储区记录返回值,函数可以有任意多个不确定类型的形式参数。这个猜测结果叫做函数的隐式声明
隐式声明里形式参数的类型只能是整数类型双精度浮点类型
如果函数的真实格式和隐式声明的格式不同则编译就会出错
函数大括号前面的部分可以单独作为一条语句使用,这种语句叫函数声明语句

STDC02_day04_04-函数11.ts

函数声明语句里可以省略形式参数名称
把函数声明语句单独写在文件开头叫函数的显式声明
函数的显式声明可避免函数的隐式声明

/CSD1702/biaoc/day09 03func.c

/*
	数组形式参数演示
*/
#include <stdio.h>
double add(double,double);	//函数声明语句里可以省略形式参数名称
int main(){
    int num = 0,num1 = 0,sum = 0;
	printf("请输入两个数字:");
    scanf("%d%d",&num,&num1);
    sum = add(num,num1);
    printf("sum是%d\n",sum);
    return 0;
}
double add(double num,double num1){
	return num + num1;
}
结果:
请输入两个数字:4 7
sum是11

一个程序里除了主函数以外的所有函数都必须显式声明

exit标准函数可以随时结束程序的执行,为了使用这个标准函数需要包含stdlib.h头文件,这个函数需要一个整数类型的实际参数,这个参数的作用和主函数返回值的作用一致

/CSD1702/biaoc/day09 04exit.c

/*
	exit标准函数演示
*/
#include <stdio.h>
void func(void){
    printf("2\n"); 
    printf("3\n");
}

int main(){
	printf("1\n");
    func();
    printf("4\n");
    return 0;
}
结果:
1
2
3
4

/CSD1702/biaoc/day09 04exit.c

/*
	exit标准函数演示
*/
#include <stdio.h>
void func(void){
    printf("2\n"); 
    return;    //跳到func函数末尾
    printf("3\n");
}

int main(){
	printf("1\n");
    func();
    printf("4\n");
    return 0;
}
结果:
1
2
4

/CSD1702/biaoc/day09 04exit.c

/*
	exit标准函数演示
*/
#include <stdio.h>
#include <stdlib.h>
void func(void){
    printf("2\n"); 
    //return;    //跳到func函数末尾
    exit(0);    //立刻结束整个程序执行
    printf("3\n");
}

int main(){
	printf("1\n");
    func();
    printf("4\n");
    return 0;
}
结果:
1
2

STDC02_day04_05-递归和递推01.ts

C语言里函数可以调用自己
能调用自己的函数叫递归函数

/CSD1702/biaoc/day09 05recur.c

/*
	递归函数演示
*/
#include <stdio.h>
void print(void){
    printf("1\n");
    print();     //函数调用函数自己
}
int main(){
    print();
    return 0;
}

结果:
1
1
1
...
无数个1

如果一个问题可以拆分成多个小问题,至少一个小问题和原来的大问题本质一样。这种问题就适合采用递归函数解决。

递归函数编写步骤:
1.编写语句解决分解后的每个小问题(假设递归函数已经可以使用
2.在函数的开头编写分支用来处理不能分解的情况,这个分支必须保证函数可以结束

/CSD1702/biaoc/day09 06recur.c

/*
	递归函数演示
*/
#include <stdio.h>
void print(int num){
    if(num == 1){
        printf("1 ");
        return;
    }
    print(num - 1);    //假设递归函数可以用了,
    printf("%d ",num);
}
int main(){
	print(10);
	printf("\n");
	return 0;
}
结果:
1 2 3 4 5 6 7 8 9 10 

采用递归函数解决问题的方法叫递归
采用循环解决类似问题的方法叫递推

练习:
编写递归函数计算从1开始到某个正整数之间所有整数的和。

STDC02_day04_06-递归和递推02.ts

/CSD1702/biaoc/day09 07recur.c

/*
	递归函数练习
*/
#include <stdio.h>
int sum(int num){
    if(num == 1){
        return 1;
    }
    return sum(num - 1) + num;
}
int main(){
    int num = 0;
    printf("请输入一个数字:");
    scanf("%d",&num);
    printf("求和结果是%d\n",sum(num));
    return 0;
}
结果:
请输入一个数字:10
求和结果是55

练习:

1 1 2 3 5 8 13 21....
0 1 2 3 4 5  6  7.....

编写递归函数根据编号计算对应的数字

STDC02_day04_07-变量和作用域01.ts

/CSD1702/biaoc/day09 08fei.c

/*
	递归函数练习
*/
#include <stdio.h>
int fei(int num){
    if(num <= 1){
        return 1;
    }    
    return fei(num - 1) + fei(num - 2);
}
int main(){
    int num = 0;
    printf("请输入一个编号:");
    scanf("%d",&num);
    printf("数字是%d\n",fei(num));
    return 0;
}
结果:
请输入一个编号:5
数字是8

C语言里变量只能被一部分语句使用,这些语句叫做这个变量的作用域
声明在函数里的变量叫局部变量,局部变量的作用域只包含函数内部的语句。
声明在所有函数外部的变量叫全局变量,这种变量的作用域包含程序中的所有语句

/CSD1702/biaoc/day09 09var.c

/*
	作用域演示
*/
#include <stdio.h>
int num1;		    //全局变量
void func(void){
    int num = 10;	//局部变量
}
int main(){
    printf("num是%d\n",num);
    return 0;
}
结果:
编译出错,不能输出num变量的值

/CSD1702/biaoc/day09 09var.c

/*
	作用域演示
*/
#include <stdio.h>
int num1;		    //全局变量
void func(void){
    int num = 10;	//局部变量
    printf("num1是%d\n",num1);
}
int main(){
    //printf("num是%d\n",num);    错误
    func();
    printf("num1是%d\n",num1);
    return 0;
}
结果:
num1是0
num1是0

没有初始化的全局变量会自动被初始化成0

STDC02_day04_08-变量和作用域02.ts

局部变量和全局变量可以重名,这个变量名优先代表局部变量

/CSD1702/biaoc/day09 09var.c

/*
	作用域演示
*/
#include <stdio.h>
int num1;		    //全局变量
void func(void){
    int num1 = 100;
    int num = 10;	//局部变量
    printf("num1是%d\n",num1);
}
int main(){
    //printf("num是%d\n",num);
    func();
    printf("num1是%d\n",num1);
    return 0;
}
结果:
num1是100
num1是0

程序中如果局部变量和全局变量都能解决问题应该优先考虑采用局部变量

存储区的使用不受作用域限制(可以跨函数使用存储区)(用数组做形式参数)
存储区的使用受到生命周期的限制
生命周期指一段时间,在声明周期开始时计算机把存储区分配给程序使用,在生命周期结束时计算机把程序使用的存储区收回
全局变量的生命周期是整个程序执行时间,
局部变量的生命周期是函数一次执行的时间范围,函数开始执行的时候计算机把存储区分配给程序使用,函数结束的时候计算机把存储区回收
如果函数多次执行则每次执行时计算机都会给它分配存储区,每次分配的存储区可能不同

/CSD1702/biaoc/day09 10var.c

/*
	生命周期演示
*/
#include <stdio.h>
void func(void){
    int num;
    printf("num是%d\n",num);
    num = 10;    
}
void func1(void){
    int num = 100;
    func();
}
int main(){
    func();
    func1();
    return 0;
}
DEV C++结果:
num是0
num是0
视频结果:
num是-1218579915
num是134513662  (第二次显示结果不是10)

STDC02_day04_09-变量和作用域03.ts

声明变量的时候可以使用static关键字,这种变量叫做静态变量
静态变量的生命周期是整个程序执行时间
只要程序没有结束,在静态变量的存储区都可以使用
如果一个函数多次执行则每次执行的时候静态局部变量对应的存储区都是同一个
/CSD1702/biaoc/day09 10var.c

/*
	生命周期演示
*/
#include <stdio.h>
void func(void){
    static int num;		//静态局部变量
    printf("num是%d\n",num);
    num = 10;
}
void func1(void){
    int num = 100;
    func();
}
int main(){
    func();
    func1();
    return 0;
}
DEV C++结果:
num是0
num是10
视频结果:
num是0
num是10

没有初始化的静态变量会自动被初始化成0

/CSD1702/biaoc/day09 10var.c

/*
	生命周期演示
*/
#include <stdio.h>
void func(void){
    static int num = 1000;		//静态局部变量
    printf("num是%d\n",num);
    num = 10;
}
void func1(void){
    int num = 100;
    func();
}
int main(){
    func();
    func1();
    return 0;
}
结果:
num是1000
num是10

静态变量的初始化只在程序开始的时候执行一次

全局变量的生命周期是整个程序执行时间,作用域是整个程序中所有语句
静态全局变量的作用域只包含声明它的文件里面的所有语句(不可以跨文件使用静态全局变量的)(多文件编程时演示)

静态局部变量的作用域不变(普通局部变量作用域),生命周期相比普通局部变量拉长为整个只包含声明它的文件里面的所有语句

静态局部变量的作用域不变,生命周期被拉长,静态全局变量的生命周期不变(普通全局变量生命周期),作用域被压缩了

STDC02_day04_10-指针01.ts

指针变量用来记录地址数据
指针变量是用来找到另外一个普通变量的
只有记录有效地址的指针才能使用
声明指针变量的时候要在变量名称前加*

/CSD1702/biaoc/day09 11ptr.c

/*
	指针演示
*/
#include <stdio.h>
int main(){
    int num = 0;
    int *p_num;		//指针变量声明
    p_num = &num;   //将变量num取地址赋值给指针变量p_num
    *p_num = 10;    //将10赋值给p_num地址的存储区  *p_num取p_num地址的内容
    printf("num是%d\n",num);
    return 0;
}
结果:
num是10

捆绑过的指针前使用*操作符可以表示指针捆绑的存储区

指针也分类型,不同类型的指针适合与不同类型的存储区捆绑(声明指针的时候有类型int等)

可以在一条语句里声明多个同类型的指针变量,这个时候需要在每个指针变量名称前单独加*

/CSD1702/biaoc/day09 11ptr.c

/*
	指针演示
*/
#include <stdio.h>
int main(){
    int num = 0;
    int *p_num,*p_num1;		//指针变量声明
    p_num = &num;
    *p_num = 10;
    printf("num是%d\n",num);
    return 0;
}
结果:
num是10

没有捆绑过的指针分成以下两类:
1.空指针记录空地址(NULL),这个地址的数值就是数字0
2.其他没有捆绑过的指针都叫野指针

程序里禁止出现野指针
所有指针变量必须初始化

/CSD1702/biaoc/day09 11ptr.c

/*
	指针演示
*/
#include <stdio.h>
int main(){
    int num = 0;
    int *p_num = NULL,*p_num1 = &num;//指针变量声明   *表示变量是个指针类型
    p_num = &num;
    *p_num = 10;     //*表示取指针变量的存储区内容
    printf("num是%d\n",num);
    return 0;
}

指针变量初始化的时候*没有参与赋值过程

指针变量声明时的*表示变量是个指针类型
对指针所表示的地址取内容的时候的*表示取内容符号

STDC02_day04_11-指针02.ts

练习:
1 1 2 3 5 8 13 21…
0 1 2 3 4 5 6 7…
编写递归函数根据编号计算对应的数字

​ 40
​ 38 39
​ 36 37 37 38
重复计算导致程序结果输出变慢

/CSD1702/biaoc/day09 12fei.c

/*
	递归函数练习
*/
#include <stdio.h>
int fei(int num){
    int arr[50] = {0};     //把算出的数字放在数组里
    if(num <= 1){
        return 1;
    }    
    if (!arr[num - 2]) {	//如果arr[num - 2]不是0,这个算过并且已经放到数组中 求反表示数组里没有这个数
        arr[num - 2] = fei(num - 2);    //当没有这个数的时候
    }
    if (!arr[num - 1]) {	//如果这个数没有算过
        arr[num - 1] = fei(num - 1);
    }
    return arr[num - 2] + arr[num - 1];   //这两个存储区一定有数
}
int main(){
    int num = 0;
    printf("请输入一个编号:");
    scanf("%d",&num);
    printf("数字是%d\n",fei(num));
    return 0;
}
结果:
请输入一个编号:40             
数字是165580141               //时间更长

用三种方法改造这个程序,让程序快起来

/CSD1702/biaoc/day09 12fei.c

/*
	递归函数练习
*/
#include <stdio.h>
int arr[50];		//定义为全局变量,不需要初始化,没有初始化自动初始化成0
int fei(int num){
    //int arr[50] = {0};//问题来自于数组是个局部变量,每次执行fei函数都重新定义一个数组
    if(num <= 1){
        return 1;
    }    
    if (!arr[num - 2]) {	//如果这个数没有算过
        arr[num - 2] = fei(num - 2);
    }
    if (!arr[num - 1]) {	//如果这个数没有算过
        arr[num - 1] = fei(num - 1);
    }
    return arr[num - 2] + arr[num - 1];
}
int main(){
    int num = 0;
    printf("请输入一个编号:");
    scanf("%d",&num);
    printf("数字是%d\n",fei(arr,50,num));
    return 0;
}
结果:
请输入一个编号:40
数字是165580141

/CSD1702/biaoc/day09 12fei.c

/*
	递归函数练习
*/
#include <stdio.h>
int fei(int num){
    static int arr[50] = {0};//定义为静态数组
    if(num <= 1){
        return 1;
    }    
    if (!arr[num - 2]) {	//如果这个数没有算过
        arr[num - 2] = fei(num - 2);
    }
    if (!arr[num - 1]) {	//如果这个数没有算过
        arr[num - 1] = fei(num - 1);
    }
    return arr[num - 2] + arr[num - 1];
}
int main(){
    int num = 0;
    printf("请输入一个编号:");
    scanf("%d",&num);
    printf("数字是%d\n",fei(num));
    return 0;
}
结果:
请输入一个编号:40
数字是165580141

/CSD1702/biaoc/day09 12fei.c

/*
	递归函数练习
*/
#include <stdio.h>		
int fei(int arr[],int size,int num){//fei函数增加数组形参,增加一个整数形参
    //int arr[50] = {0};		//问题来自于数组是个局部变量,每次执行fei函数都重新定义一个数组
    if(num <= 1){
        return 1;
    }    
    if (!arr[num - 2]) {	//如果这个数没有算过
        arr[num - 2] = fei(arr,size,num - 2);
    }
    if (!arr[num - 1]) {	//如果这个数没有算过
        arr[num - 1] = fei(arr,size,num - 1);
    }
    return arr[num - 2] + arr[num - 1];
}
int main(){
    int num = 0;
    int arr[50] = {0};	//声明在主函数中,生命周期是主函数的执行时间,由于是局部变量,需要初始化
    printf("请输入一个编号:");
    scanf("%d",&num);
    printf("数字是%d\n",fei(arr,50,num));
    return 0;
}
结果:
请输入一个编号:40
数字是165580141

预习:
​ 1.指针
​ 2.字符串

day5: 指针02 、 字符串01

STDC02_day05_01-指针03.ts

练习:
编写程序从键盘得到三个整数,将三个整数从大到小输出,使用指针解决

/CSD1702/biaoc/day10 01ptr.c

/*
	指针练习
*/
#include <stdio.h>
int main(){
    int num = 0, num1 = 0, num2 = 0, tmp = 0;
    int *p_num = &num, *p_num1 = &num1, *p_num2 = &num2, *p_tmp = &tmp;
    printf("请输入三个数字:");
    scanf("%d%d%d",p_num,p_num1,p_num2);
    if(*p_num < *p_num1){
        *p_tmp = *p_num;
        *p_num = *p_num1;
        *p_num1 = *p_tmp;
    }
    if(*p_num < *p_num2){
        *p_tmp = *p_num;
        *p_num = *p_num2;
        *p_num2 = *p_tmp;
    }
    if(*p_num1 < *p_num2){
        *p_tmp = *p_num1;
        *p_num1 = *p_num2;
        *p_num2 = *p_tmp;
    }
    //补充:三个if语句实现了将变量中从大到小实际为num,num1,num2,变量的值实际也发生了变化
    printf("%d %d %d\n",*p_num,*p_num1,*p_num2);
    return 0;
}
结果:
请输入三个数字:45 23 87
87 45 23

/CSD1702/biaoc/day10 01ptr.c

/*
	指针练习
*/
#include <stdio.h>
int main(){
    int num = 0, num1 = 0, num2 = 0, tmp = 0;
    int *p_num = &num, *p_num1 = &num1, *p_num2 = &num2, *p_tmp = &tmp;
    printf("请输入三个数字:");
    scanf("%d%d%d",p_num,p_num1,p_num2);
    /*if(*p_num < *p_num1){
        *p_tmp = *p_num;
        *p_num = *p_num1;
        *p_num1 = *p_tmp;
    }
    if(*p_num < *p_num2){
        *p_tmp = *p_num;
        *p_num = *p_num2;
        *p_num2 = *p_tmp;
    }
    if(*p_num1 < *p_num2){
        *p_tmp = *p_num1;
        *p_num1 = *p_num2;
        *p_num2 = *p_tmp;
    }*/
    if(*p_num < *p_num1){
        p_tmp = p_num;
        p_num = p_num1;
        p_num1 = p_tmp;       
    }
    if(*p_num < *p_num2){
        p_tmp = p_num;
        p_num = p_num2;
        p_num2 = p_tmp;       
    }
    if(*p_num1 < *p_num2){
        p_tmp = p_num1;
        p_num1 = p_num2;
        p_num2 = p_tmp;       
    } 
    //补充:实现了将p_num,p_num1,p_num2分别最大、中间、最小的变量捆绑,变量的值不会改变
    printf("%d %d %d\n",*p_num,*p_num1,*p_num2);
    return 0;
}
结果:
请输入三个数字:56 87 23
87 56 23

指针和存储区之间的捆绑关系可以随着程序的执行而改变
指针可以用来代表存储区的某种特征

STDC02_day05_02-指针04.ts

如果指针和数组里的第一个存储区捆绑,通过这个指针可以找到数组里的每个存储区
在指针后加下标就可以找到数组里下标对应的存储区

/CSD1702/biaoc/day10 02ptr.c

/*
	指针演示
*/
#include <stdio.h>
int main(){
    int arr[] = {1,2,3,4,5},num = 0;
    int *p_num = arr;    //数组名称当做地址赋值给指针
    for(num = 0;num <= 4;num++){
        printf("%d ",arr[num]);   //补充:数组名的本质是一个指针常量
        printf("%d ",p_num[num]);
    }
    printf("\n");
    return 0;
}
结果:
1 1 2 2 3 3 4 4 5 5

地址数据可以参与如下计算
地址 + 整数 地址 - 整数 地址 - 地址
地址数据加减整数n实际上加减的是n个捆绑存储区的大小

/CSD1702/biaoc/day10 02ptr.c

/*
	指针演示
*/
#include <stdio.h>
int main(){
    int arr[] = {1,2,3,4,5},num = 0;
    int *p_num = arr;
    for(num = 0;num <= 4;num++){
        printf("%d ",arr[num]); 
        printf("%d ",p_num[num]);
    }
    printf("\n");
    printf("arr是%p,arr + 3是%p,arr - 3是%p,&arr[3]是%p\n",arr,arr + 3,arr - 3,&arr[3]);
    return 0;
}
结果:
1 1 2 2 3 3 4 4 5 5 
arr是0x7fffb728f750,arr + 3是0x7fffb728f75c,arr - 3是0x7fffb728f744,&arr[3]是0x7fffb728f75c(加3和减3代表3个存储区大小)

数组第一个存储区地址加下标,结果是下标对应存储区的地址
可以采用如下写法表示数组里下标为num的存储区
*(arr + num)

/CSD1702/biaoc/day10 02ptr.c

/*
	指针演示
*/
#include <stdio.h>
int main(){
    int arr[] = {1,2,3,4,5},num = 0;
    int *p_num = arr;
    for(num = 0;num <= 4;num++){
        printf("%d ",arr[num]); 
        printf("%d ",p_num[num]);
        printf("%d ",*(p_num + num));
    }
    printf("\n");
    printf("arr是%p,arr + 3是%p,arr - 3是%p,&arr[3]是%p\n",arr,arr + 3,arr - 3,&arr[3]);
    return 0;
}
结果:
1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 
arr是0x7fff66bb3cb0,arr + 3是0x7fff66bb3cbc,arr - 3是0x7fff66bb3ca4,&arr[3]是0x7fff66bb3cbc

地址之间做减法结果是一个整数,这个整数表示两个地址之间包含的捆绑存储区个数

/CSD1702/biaoc/day10 02ptr.c

/*
	指针演示
*/
#include <stdio.h>
int main(){
    int arr[] = {1,2,3,4,5},num = 0;
    int *p_num = arr;
    for(num = 0;num <= 4;num++){
        printf("%d ",arr[num]); 
        printf("%d ",p_num[num]);
        printf("%d ",*(p_num + num));
    }
    printf("\n");
    printf("arr是%p,arr + 3是%p,arr - 3是%p,&arr[3]是%p\n",arr,arr + 3,arr - 3,&arr[3]);
    printf("&arr[3] - arr是%d\n",&arr[3] - arr);
    return 0;
}
结果:
1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 
arr是0x7fffa7d9d7e0,arr + 3是0x7fffa7d9d7ec,arr - 3是0x7fffa7d9d7d4,&arr[3]是0x7fffa7d9d7ec
&arr[3] - arr是3

STDC02_day05_03-指针05.ts

声明指针变量的时候(常见)可以使用const关键字
可以在声明指针变量的时候把const关键字写在
类型名称前

程序中不可以通过这种指针对它捆绑的存储区做赋值,但是可以对指针本身做赋值

/CSD1702/biaoc/day10 03const.c

/*
	指针演示
*/
#include <stdio.h>
int main(){
    int num = 0;    //声明一个整型变量
    const int *p_num = &num;    //声明指针和整数类型存储区捆绑,使用const关键字
    //*p_num = 10;    //用const关键字修饰的指针不可以通过它对它所捆绑的存储区做赋值    错误
    p_num = NULL;    //可对指针本身做赋值
    return 0;
}

可以在声明指针变量的时候把const关键字写在指针变量名称前
可以通过这种指针对它捆绑的存储区做赋值,但是不可以对这种指针本身做赋值

/CSD1702/biaoc/day10 03const.c

/*
	指针演示
*/
#include <stdio.h>
int main(){
    int num = 0;
    const int *p_num = &num;    //声明指针和整数类型存储区捆绑,使用const关键字
    int * const p_num1 = &num;    //const关键字写在指针变量名称前,可以对存储区做赋值,不能对指针本身做赋值
    //*p_num = 10;    //用const关键字修饰的指针不可以通过它对它所捆绑的存储区做赋值    错误
    p_num = NULL;    //可对指针本身做赋值
    *p_num1 = 10;    //可以对指针所捆绑的存储区做赋值
    p_num1 = NULL;    //不可以对指针本身走赋值
    return 0;
}

可以在声明指针的时候使用void作为类型名称,这种指针叫做无类型指针
这种指针可以和任意类型的存储区捆绑
无法通过这种指针知道捆绑的存储区的类型
不应该在无类型指针前加*也不应该对它做加减整数的计算
这种指针必须首先强制类型转换成有类型指针然后才能使用

STDC02_day05_04-指针06.ts

/CSD1702/biaoc/day10 04void.c

/*
	无类型指针演示
*/
#include <stdio.h>
int main(){
    char ch = 'r';
    int num = 34;
    float fnum = 5.6f;
    void *p_v = &ch;
    printf("%c\n",*(char *)p_v);
    p_v = &num;
    printf("%d\n",*(int *)p_v);
    p_v = &fnum;
    printf("%g\n",*(float *)p_v);
    return 0;
}
结果:
r
34
5.6

所有的跨函数使用存储区都是通过指针实现的
数组做形式参数的时候真正的形式参数是一个指针

/CSD1702/biaoc/day10 05ptr.c

/*
	指针形式参数演示
*/
#include <stdio.h>
void print(int arr[],int size){
    int num = 0;
    for(num = 0;num <= size - 1;num++){
        printf("%d ",arr[num]);
    }
    printf("\n");
}
int main(){
    int arr[] = {1,2,3,4,5};
	print(arr,5);
    return 0;
}
结果:
1 2 3 4 5

/CSD1702/biaoc/day10 05ptr.c

/*
	指针形式参数演示
*/
#include <stdio.h>
void print(int *p_num,int size){
    int num = 0;
    for(num = 0;num <= size - 1;num++){
        printf("%d ",*(p_num + num));
    }
    printf("\n");
}
int main(){
    int arr[] = {1,2,3,4,5};
	print(arr,5);
    return 0;
}
结果:
1 2 3 4 5

练习:
编写函数把主函数里两个存储区的内容做交换

STDC02_day05_05-指针07.ts

/CSD1702/biaoc/day10 06swap.c

/*
	指针形式参数练习
*/
#include <stdio.h>
void swap(int *p_num,int *p_num1){
    int tmp = 0;
    tmp = *p_num;      //补充:如果把*去掉,不能完成任务
    *p_num = *p_num1;  //补充:指针形参的存储区是被调函数提供的,不能够影响主函数
    *p_num1 = tmp;
}
int main(){
    int num = 0,num1 = 0;
    printf("请输入两个数字:");
    scanf("%d%d",&num,&num1);
    swap(&num,&num1);
    printf("num是%d,num1是%d\n",num,num1);
    return 0;
}
结果:
请输入两个数字:1 2
num是2,num1是1

声明指针形式参数的时候应该尽可能在类型名称前使用const关键字
补充:表示不同通过这个指针对它所捆绑的存储区做赋值,为了告诉调用函数不会修改指针形参所捆绑的存储区内容

/CSD1702/biaoc/day10 06swap.c

/*
	指针形式参数练习
*/
#include <stdio.h>
void swap(int *p_num,int *p_num1){	//补充:不能对指针形参类型名称加const关键字,程序中要给指针形参所捆绑的存储区做赋值
    int tmp = 0;
    tmp = *p_num;      //补充:如果把*去掉,不能完成任务
    *p_num = *p_num1;  //补充:指针形参的存储区是被调函数提供的,不能够影响主函数
    *p_num1 = tmp;
}
int main(){
    int num = 0,num1 = 0;
    printf("请输入两个数字:");
    scanf("%d%d",&num,&num1);
    swap(&num,&num1);
    printf("num是%d,num1是%d\n",num,num1);
    return 0;
}
结果:
请输入两个数字:4 8
num是8,num1是4

/CSD1702/biaoc/day10 05ptr.c

/*
	指针形式参数演示
*/
#include <stdio.h>
void print(const int *p_num,int size){	//补充:能对指针形参类型名称加const关键字,程序中不给指针形参所捆绑的存储区做赋值
    int num = 0;
    for(num = 0;num <= size - 1;num++){
        printf("%d ",*(p_num + num));
    }
    printf("\n");
}
int main(){
    int arr[] = {1,2,3,4,5};
	print(arr,5);
    return 0;
}
结果:
1 2 3 4 5

无类型指针通常作为形式参数使用
使用地址作为返回值可以让调用函数使用被调用函数提供的存储区
这个时候被调用函数需要提供一个指针类型的存储区记录作为返回值的地址
不可以把非静态局部变量的地址作为返回值使用

/CSD1702/biaoc/day10 07ptr.c

/*
	地址返回值演示
*/
#include <stdio.h>
int *read(void){
    static int num = 0;	//将变量变成静态变量可以把变量的生命周期拉长
    printf("请输入一个数字:");
    scanf("%d",&num);
    return &num;	//不可把非静态局部变量的地址作为返回值使用
}
int main(){
    int *p_num = read();
    printf("数字是%d\n",*p_num);
    return 0;
}
结果:
请输入一个数字:45
数字是45

补充:

/CSD1702/biaoc/day10 07ptr.c

/*
	地址返回值演示
*/
#include <stdio.h>
int *read(int *p_num){	//对read函数提供一个整数类型指针的形式参数
    //static int num = 0;	//将变量变成静态变量可以把变量的生命周期拉长
    printf("请输入一个数字:");
    scanf("%d",p_num);
    return p_num;
}
int main(){
    int num1 = 0;    //定义一个整型变量
    int *p_num1 = &num1;    //定义一个指针,与变量的地址捆绑
    printf("数字是%d\n",*read(p_num1));
    return 0;
}
结果:
请输入一个数字:45
数字是45

练习:
编写一个函数从一个数组里找到最大数字所在的存储区并把这个存储区的地址传递给调用函数

STDC02_day05_06-指针08.ts

/CSD1702/biaoc/day10 08ptr.c

/*
	指针练习
*/
#include <stdio.h>
int *max(const int *p_num,int size){	//补充:不会修改存储区所捆绑的内容
    const int *p_tmp = NULL,*p_max = NULL;	//声明指针作为循环变量
    //按顺序依次处理数组里每个存储区,地址加数字n表示增加了n个存储区的大小
    for(p_tmp = p_num;p_tmp <= p_tmp + size - 1;p_tmp++){
        //两种情况:一个是p_max为空,另外p_max所捆绑的存储区内容比p_tmp的小
        if(!p_max || *p_max < *p_tmp){    //
            p_max = p_tmp;
        }    
    }
    return (int *)p_max;	//变量声明有const关键字,为了避免警告需要强制转换
}
int main(){
    int arr[] = {34,62,15,22,41};
    int *p_num = max(arr, 5);
    printf("最大的数字是%d\n", *p_num);
    return 0;
}
结果:
最大的数字是62

STDC02_day05_07-字符串01.ts

C语言中所有文字信息必须记录在一组连续的字符类型存储区里
所有文字信息必须以’\0‘字符作为结尾,这个字符的ASCII码就是0
符合以上两个特征的内容叫字符串,它们可以用来表示文字信息
字符串里’\0‘字符前面的内容是有效文字信息
所有字符串都可以使用一个字符类型指针表示

字符串字面值是一种字符串,用两个双引号中间的一组字符表示(例如:"abc","^&&"等)
编译器在编译的时候会自动在字符串字面值的末尾加上’\0‘字符
编译器会把字符串字面值替换成第一个字符所在存储区的地址

/CSD1702/biaoc/day10 09str.c

/*
    字符串演示
*/
#include <stdio.h>
int main(){
    printf("%p\n","abc");
    printf("%c\n",*"abc");
    return 0;
}
结果:
0x8048504
a

字符串字面值的内容在程序执行过程中不可以改变

/CSD1702/biaoc/day10 09str.c

/*
    字符串演示
*/
#include <stdio.h>
int main(){
    printf("%p\n","abc");
    printf("%c\n",*"abc");
    //*"abc" = 'r';		//字符串字面值的内容在程序执行过程中不可以改变
    return 0;
}

程序中如果有多个内容一样的字符串字面值则它们其实是同一个

/CSD1702/biaoc/day10 09str.c

/*
    字符串演示
*/
#include <stdio.h>
int main(){
    printf("%p\n","abc");         
    printf("%p\n","abc");	//两个字符串字面值一样,它们其实是同一个,有相同的地址
    printf("%c\n",*"abc");    //
    //*"abc" = 'r';		//错误    字符串字面值在程序执行过程中不能改变
    return 0;
}
结果:
0x8048504
0x8048504          
a

编译器会把多个并列的字符串字面值合并成一个

/CSD1702/biaoc/day10 09str.c

/*
    字符串演示
*/
#include <stdio.h>
int main(){
    printf("%p\n","abc");
    printf("%p\n","abc");	//补充:两个字符串字面值一样,它们其实是同一个,有相同的地址
    printf("%p\n","ab""c");	//补充:编译器将多个并列的字符串字面值合并成同一个
    printf("%c\n",*"abc");
    //*"abc" = 'r';		//错误
    return 0;
}
结果:
0x8048524
0x8048524
0x8048524
a

STDC02_day05_08-字符串02.ts

字符数组也可以用来表示字符串
只有包含’\0‘字符的字符数组才可以当做字符串使用
可以采用字符串字面值对字符数组进行初始化,这个时候计算机会把字符串字面值末尾的’\0'字符也初始化到字符数组里

/CSD1702/biaoc/day10 09str.c

/*
    字符串演示
*/
#include <stdio.h>
int main(){
    char str[] = "abcdef";	//补充:'\0'字符初始化到数组里,7个存储区
    printf("%p\n","abc");
    printf("%p\n","abc");    //补充:两个字符串字面值一样,它们其实是同一个,有相同的地址
    printf("%p\n","ab""c");    //补充:编译器将多个并列的字符串字面值合并成同一个
    printf("%c\n",*"abc");
    //*"abc" = 'r';		//错误
    printf("sizeof(str)是%d\n",sizeof(str));
    return 0;
}

结果:
0x8048524
0x8048524
0x8048524
a
sizeof(str)是7

字符数组里的字符串内容可以修改

可以在printf函数调用语句里使用%s作为占位符把字符串显示在屏幕上

/CSD1702/biaoc/day10 09str.c

/*
    字符串演示
*/
#include <stdio.h>
int main(){
    char str[] = "abcdef";	//7个存储区
    printf("%p\n","abc");
    printf("%p\n","abc");
    printf("%p\n","ab""c");
    printf("%c\n",*"abc");
    //*"abc" = 'r';		//错误
    printf("sizeof(str)是%d\n",sizeof(str));
    printf("%s\n",str);
    return 0;
}
结果:
0x8048524
0x8048524
0x8048524
a
sizeof(str)是7
abcdef

练习:
编写函数把一个数组里所有存储区的内容前后颠倒
加入数组里原有内容是1 2 3 4 5
颠倒后的内容是5 4 3 2 1
用指针编写这个函数

/CSD1702/biaoc/day10 10reverse.c

/*
	指针练习
*/
#include <stdio.h>
int *reverse(int *p_num,int size){	//补充:把数组第一个存储区地址当做返回值使用,不加const关键字
    int *p_head = p_num, *p_tail = p_num + size - 1, tmp = 0;
    while (p_head < p_tail){    //
        tmp = *p_head;		//补充:将头指针和尾指针所捆绑的存储区做交换
        *p_head = *p_tail;
        *p_tail = tmp;
        p_head++;    //交换后前面的地址+1 数字向后移1位
        p_tail--;    //交换后后面的地址-1 数字向前移1位
    }
    return p_num;    //返回数组第一个地址
}
int main(){
    int arr[] = {1,2,3,4,5},num = 0;
    int *p_num = reverse(arr,5);
    for(num = 0;num <= 4;num++){
        printf("%d ",*(p_num + num));
    }
    printf("\n");
    return 0;
}
结果:
5 4 3 2 1

预习:
​ 1.字符串
​ 2.预处理指令

猜你喜欢

转载自blog.csdn.net/u013673437/article/details/88055672