0%

03c_10day

========================
2022-7-27
========================

一.温故知新

1.求10000-11000中所有的质数
2.冒泡法排序
3.实现strcat
    char *mystrcat(char *dest, const char *src); 
字符数组和字符指针
    在C语言中是没有字符串类型的,
    想要存储字符串数据可以使用字符数组
    数组越界的问题
    ----------------------------------
    char *p = "Hello";

    字符串的操作
    strcpy strcat strcmp strlen
    mystrcpy mystrcat mystrcmp mystrlen
    ----------------------------------
    mystrncpy mystrncat mystrncmp
    ----------------------------------
    char dest[2];
    char *src = "Hello World";

    strcpy(dest, src);

    strncpy

用多文件的形式实现一下冒泡法排序

main.c sort.c sort.h makefile

vim * -p(以标签页的形式打开多文件)
切换文件 ctrl + alt + pgup/pgdn

1
2
3
4
5
6
7
#ifndef __SORT_H
#define __SORT_H




#endif
========================== 作业: 1.把今天讲过的内容完完整整的复习一遍 2.把之前讲过的功能函数都拆成多文件的形式写一遍 1)子弹的程序 2)排序(冒泡法 选择法 ...) 3)字符串操作函数(mystrcpy mystrcat mystrcmp mystrlen) 4)atoi函数功能 3.把五子棋游戏拆成多文件的形式实现 ==========================

一.写C语言程序的四个阶段

第一阶段	只写一个.c文件,在.c文件中只写一个main函数
            把所有功能都堆到main函数中
第二阶段	只写一个.c文件,在.c文件中除了main函数以外
            封装了其他的功能函数
    函数的声明
函数的返回值类型 函数名(参数列表);//该处的参数指的是形参
    函数的实现
函数的返回值类型 函数名(参数列表)//该处的参数指的是形参
{
    功能实现的代码
}
    函数的调用
函数名(参数);//该处的参数指的是实际参数
第三阶段	以项目工程的形式编写程序,以多文件的形式
            main.c		存放主函数和功能函数的调用
            func.c		存放功能函数的实现
            func.h		存放功能函数的声明以及各种定义
            makefile	存放的是编译规则
第四阶段	把功能函数的实现封装成库文件
            静态库和动态库

二.makefile文件的简介

    一个项目工程中源文件不计其数,这些源文件按照文件类型,
    功能,模块,分别存放在不同的目录中,makefile文件定义了
    一系列的规则来指定哪些文件需要先编译,
    哪些文件需要后编译,哪些文件需要重新编译
    包括更复杂的一些编译操作

三.内存空间的分布

    C语言会把内存分为5个区域
    (栈区 堆区 常量区 全局区 代码区)
    ./a.out执行程序时,是由一个进程来执行程序的
    进程的空间大小是4Gb,是由真实内存4Kb虚拟出来的

    1Gb			Kernel(内核)
    ----------------------------
    3Gb			命令行参数以及环境变量
                栈区(从上往下分配空间)

                空白

                堆区(从下往上分配空间)
                静态区(全局区)未初始化的(系统会初始化成0)
                静态区(全局区)已初始化的
                常量区(只读区)Read Only
                代码区
    栈区		不需要程序员管理,自己开辟,自己释放
    堆区		需要程序员管理,需要手动开辟,需要手动释放
                (malloc calloc realloc free)
    全局区		全局变量/static关键字修饰的变量
    常量区		Read Only
                char *p = "Hello";
                字符串常量"Hello"存储在常量区中
    代码区		程序员没有办法管理

四.全局变量和局部变量

    局部变量
        在某个函数内部定义或者块内定义的变量叫做局部变量
        局部变量只能在函数内部或者块内使用
        局部变量在函数之外是不可知的

    全局变量
        全局变量是定义在函数之外的,通常写到程序开头的位置
        全局变量在整个程序中生命周期都是有效的
        在任意函数内部都可以访问全局变量

    注意:
    全局变量和局部变量可以同名
    如果出现了同名情况,那么在执行该函数时,优先使用局部变量
    在该函数中全局变量被屏蔽

    全局变量和局部变量在定义时的区别
        当定义局部变量时,系统不会帮助初始化,
            局部变量存储的是垃圾值
        当定义全局变量时,系统会帮助初始化
            int -> 0;
            char -> '\0';
            pointer -> NULL;
    全局变量和局部变量存储空间的区别
        全局变量 : 保存在内存的静态全局区,
            占用的是静态的存储单元
            当程序运行时就被创建了,
            当程序结束时才被销毁
        局部变量 : 保存在栈区中,
            只有在局部变量所在的函数被调用时,
            系统才会帮助分配存储单元,
            当局部变量所在的函数调用结束时被释放
/*
    全局变量和局部变量
    其实在查看一个变量可以通过3个属性进行查看
    存储区域 生命周期 作用域
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <stdlib.h>

int a = 9527;
/*
全局变量
存储区域 全局区
作用域 整个文件内有效
生命周期 从定义开始到程序结束
*/

void func(void)
{
int a = 100;
/*
局部变量
存储区域 栈区
作用域 函数内有效
生命周期 从函数内定义开始到功能函数结束
*/
printf("func().a = %d\n", a);
}

void func1(void)
{
printf("func1().a = %d\n", a);
}

int main(int argc, char *argv[])
{
int a = 200;

func();

printf("main.a = %d\n", a);

func1();

{
int a = -900;
/*
块级变量
存储区域 栈区
作用域 块内有效
生命周期 从定义开始到块结束
*/
printf("块.a = %d\n", a);
}

printf("main.a = %d\n", a);

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <stdlib.h>

int myatoi(const char *nptr);
/*
1.把字符串的有效字符遍历一遍 //循环遍历
2.想办法把数字的字符转换成整型数字 //数字字符 - '0'
3.想办法把整型数字存储起来
====================================================
4.处理空格的问题
5.处理正负号的问题
*/
int myatoi(const char *nptr)//"9527"
{
int i = 0;
int num = 0;
int flag = 1;//用来标记正负

for(i = 0; nptr[i] == ' '; i++); //为了跳过空格

if(nptr[i] == '-' || nptr[i] == '+')//正负号的判断
{
flag = nptr[i] == '+' ? 1 : -1;
i++;
}
for(; nptr[i] != '\0'; i++)
{
switch(nptr[i])
{
case '0' ... '9' :
num *= 10;
num += nptr[i] - '0';
break;
default : return num * flag;
}
}
return num * flag;
}

int main(int argc, char *argv[])
{
int num = 0;

num = myatoi("- 9527");

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

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#ifndef __ADD_H//为了防止头文件被重复包含
#define __ADD_H

int add(int , int );//函数的声明

#endif

----------------------------------------------------------

#include "add.h"

int add(int a, int b)
{
return a + b;
}

----------------------------------------------------------

#include <stdio.h>
#include "add.h"

int main(void)
{
int a = 0, b = 0;
int sum = 0;

scanf("%d-%d", &a, &b);

sum = add(a, b);

printf("sum = %d\n", sum);

return 0;
}

----------------------------------------------------------

# 注意:makefile文件是脚本文件,所以想要注释需要用 #
# 注意:makefile文件是非常注重格式的,空格是空格,tab是tab
# 生成的文件 : 依赖的文件(:以左是生成文件,:以右是依赖文件)
main : main.o add.o
gcc main.o add.o -o main
# 注意:使用的工具和上边生成文件的内容要差一个tab
main.o : main.s
gcc -c main.s -o main.o
main.s : main.i
gcc -S main.i -o main.s
main.i : main.c
gcc -E main.c -o main.i
add.o : add.s
gcc -c add.s -o add.o
add.s : add.i
gcc -S add.i -o add.s
add.i : add.c
gcc -E add.c -o add.i
clean :
rm -rf *.i *.s *.o main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifndef __MAX_H
#define __MAX_H

int max(int a, int b);

#endif

----------------------------------------------------------

#include "max.h"

int max(int a, int b)
{
return a > b ? a : b;
}

----------------------------------------------------------

#include <stdio.h>
#include "max.h"

int main(void)
{
int a = 0, b = 0;
int sum = 0;

scanf("%d-%d", &a, &b);

sum = max(a, b);

printf("sum = %d\n", sum);

return 0;
}

----------------------------------------------------------

main : main.o max.o
gcc -o main main.o max.o
clean :
rm -rf *.o main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#ifndef __SWAP_H
#define __SWAP_H

void swap(int *, int *);

#endif

----------------------------------------------------------

#include "swap.h"

void swap(int *a, int *b)
{
int tmp = 0;

tmp = *a;
*a = *b;
*b = tmp;
}

----------------------------------------------------------

#include <stdio.h>
#include "swap.h"

int main(void)
{
int a = 0, b = 0;

scanf("%d-%d", &a, &b);

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

swap(&a, &b);

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

return 0;
}

----------------------------------------------------------

# 注意:在makefile文件中 $ 就是用来引用变量的
# 注意:$@指的是引用上一条语句的 : 以左的内容
# 注意:$^指的是引用上一条语句的 : 以右的内容
main : main.o swap.o
gcc -o $@ $^
#等价于 gcc -o main main.o swap.o
clean :
rm -rf *.o main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#ifndef __INC_H
#define __INC_H

int arr[15][15];//棋盘
int x, y;//坐标
int flag;//标记玩家

void init(void);//初始化棋盘
void draw(void);//画棋盘
void print_infor(void);//打印玩家信息
void check(void);//检测坐标是否合理
int win(void);//判断是否可以赢

#endif

----------------------------------------------------------

#include "inc.h"

void init(void)
{
int i = 0, j = 0;

for(i = 0; i < 15; i++)
{
for(j = 0; j < 15; j++)
{
arr[i][j] = 0;//棋盘清零
}
}
x = y = 0;//坐标清零
flag = 1;//标记置为1
}

----------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include "inc.h"

void draw(void)//画棋盘
{
int i = 0, j = 0;

system("clear");
printf(" 1 2 3 4 5 6 7 8 9 A B C D E F\n");
for(i = 0; i < 15; i++)
{
printf("%X ", i + 1);
for(j = 0; j < 15; j++)
{
switch(arr[i][j])
{
case 0 : printf("+ "); break;
case 1 : printf("O "); break;
case 2 : printf("X "); break;
}
}
printf("\n");
}
}

----------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include "inc.h"

void print_infor(void)//打印玩家信息
{
printf("Player %d > ", flag);
}

#include <stdio.h>
#include "inc.h"

void check(void)//检测坐标是否合理
{
if(x < 1 || x > 15 || y < 1 || y > 15)
printf("下出了棋盘边界,请重新下棋!\n");
else if(arr[x - 1][y - 1] != 0)
printf("下到了重复位置,请重新下棋!\n");
else
{
arr[x-1][y-1] = flag;
flag ^= 3;
}
}

----------------------------------------------------------

#include "inc.h"

int win(void)//判断是否可以赢
{
return 1;
}

----------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include "inc.h"

int main(int argc, char *argv[])
{
init();//初始化棋盘

do
{
draw();//画棋盘
print_infor();//打印玩家信息
scanf("%d-%d", &x, &y);
check();//检测录入的坐标是否合理
}while(win());//如果赢了win()返回0,否则返回1

return 0;
}

----------------------------------------------------------

five : main.o init.o draw.o print.o check.o win.o
gcc -o $@ $^
clean :
rm -rf *.o five