C语言基础(2023/11/27~12/12)

D1.Linux终端指令和基本使用

第一天上课,线上上课

作业:

  1. 整理思维导图
  2. 课上练习重新写一遍
  3. 思维导图晚上十一点前发在群里

D2.vim,gcc和数据类型

第二天线上,有点难跟上

作业:

  1. 整理思维导图,复习课上内容

  2. 课上的宏定义练习再做一遍

  3. 计算下面宏定义的结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    1、求NUM的结果
    #define N 8
    #define M N+3*N
    #define NUM M*N+N/5+M*7

    8+3*8*8+8/5+8+3*8*7
    8+192+1+8+168 = 377

    2、求以下程序的输出结果
    #include
    #define ADD(a,b) a+b
    int main()
    {
    printf("%d\n",ADD(3,9));
    return 0;
    }
  4. 背会7种基本数据类型

  5. 作业完成十点前截图发群里(所有)

D3.原反补码和运算符

回看课程笔记感觉今天讲的挺重要的……

作业:

  1. signed char c = 129; %d输出的结果(所有低于4Byte的数据,在运算时都补成4Byte的有符号数,高位补符号位)

    c = 255,%d输出的结果

    c = 213,%d输出的结果

  2. 使用宏定义完成+、-、*、/和%功能,

    要求:/可以实现两数整除

    如:10/4 结果为2.5

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdio.h>
    #define DIV(a,b) a/b
    int main(int argc, const char *argv[])
    {
    int num1 = 10,num2 = 4;
    printf("%f\n",DIV((float)num1,num2));
    //(float)10/4
    return 0;
    }
  3. 整理思维导图

  4. 整理课上scanf吸收垃圾字符的代码

  5. 理解getchar获取和putchar输出的逻辑

  6. 有问题及时问

  7. 作业十一点前截图发到群里

D4.语法结构-if,switch case

哎,好多事情要忙

作业:

  1. 整理思维导图

  2. 有unsigned int a; 给第7个bit位置1,给第9个bit位置0,给第21个bit位取反

    1
    2
    3
    a|=(0x1<<7)
    a&=~(0x1<<9)
    a^=(0x1<<21)
  3. .将data中的第7:4置1,保持其他位不变

    1
    data|=(0xF<<4)
  4. 终端输入一个字符,判断是大写字母、小写字母、数字字符还是其他字符;如果是大写字母转成小写字母,如果是小写字母转换成大写字母,如果是数字字符,转换成对应的整形,如果是其他字符转换成#

  5. 复习课上练习和代码(运算符优先级,逻辑运算部分的练习多看看)

  6. 晚上十一点前交作业

D.5循环结构

嗯,今天状态不错不但听进去了,还跟着写练习,快夸我好棒!第一周的学习告一段落,给我的感受是还行:-)

作业:

  1. 整理思维导图

  2. 终端输入行数,打印金字塔

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <stdio.h>

    void main(){
    printf("请输入行数:");
    int l=0;
    scanf("%d",&l);
    int ll=l,i=0;
    while(l>0){
    while(i<=2*ll-l){
    if(i>=l){
    printf("⏹️");
    }else{
    printf(" ");
    }
    i++;
    }
    printf("\n");
    i=0;
    l--;
    }
    }

  3. 打印倒九九乘法表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>
    void main(){
    int i=1,j=1;
    while(i<=9){
    while(j<=9){
    printf("%dx%d=%d ",j,i,i*j);
    j++;
    }
    j=i+1;
    printf("\n");
    i++;
    }
    }
  4. 思考两数交换的方法

  • 引入第三个变量?
  1. 整理课上的所有代码

  2. 百钱买百鸡问题:我国古代数学家张丘建在《算经》一书中曾提出过著名的 “百钱买百鸡” 问题,该问题叙述如下:鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一;百钱买百鸡,则翁、母、雏各几何?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <stdio.h>

    void main(){
    int cock=0,hen=0,small=0;
    while(cock<=100){
    while(hen<=100){
    while(small<=100){
    if((cock*15+hen*9+small)==300 && (cock+hen+small)==100){
    printf("🐓=%d,🐔=%d,🐥=%d\n",cock,hen,small);
    }
    small+=3;
    }
    small=0;
    hen++;
    }
    hen=0;
    cock++;
    }
    }
  3. 打印字母图形

  4. 周日十一点前交作业

D6.for循环,冒泡排序

作业:

1.思维导图

2.输入一个数,计算是否是完数

​ 完数:除本身约数和等于本身

​ eg:6: 1 2 3 6

​ 1+2+3==6

3.循环输入n个元素存到数组,计算数组中素数的个数

4.循环输入数组,实现冒泡降序排序,循环输出

5.循环输入数组,计算第二大值

int arr[]={12,33,24,33,13};

第二大值计算24

D7.字符数组+二维数组

D8.函数

1.输入一个字符串,计算空格的个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main(int argc, const char *argv[]){
char arr[20];
gets(arr);

size_t count=0;

for (int i = 0; arr[i]!='\0' ; i++){
if(arr[i]==' '){
count++;
}
}

printf("空格的个数是:%ld\n",count);

return 0;
}

在这里插入图片描述

2.输入一个字符串,计算单词的个数
eg: “good good study”(空格的格式可能是多个)
单词的个数是3,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 #include <stdio.h>

int main(int argc, const char *argv[]){
char arr[20];
gets(arr);

size_t count=0;

int i =0;

while(arr[i]!='\0'){

if(arr[i]!=' ' && (arr[i+1]==' '||arr[i+1]=='\0')){
count++;
}

i++;
}

printf("单词的个数是:%ld\n",count);

return 0;
}

在这里插入图片描述

3.矩阵相乘:前提条件A矩阵的列数需要和B矩阵的行数相同
在这里插入图片描述

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
#include <stdio.h>

int main(int argc, const char *argv[]){
int line1=0,cow1=0;
printf("line1 cow1:");
scanf("%d %d",&line1,&cow1);
int line2=0,cow2=0;
printf("line2 cow2:");
scanf("%d %d",&line2,&cow2);

if(cow1!=line2){
printf("error!\n");
return 0;
}

int a[line1][cow1],b[line2][cow2],ans[20][20]={0};

printf("a:\n");
for (int i = 0; i < line1 ; i++){
for (int j = 0; j < cow1; j++){
scanf("%d",&a[i][j]);
}
}

printf("b:\n");
for (int i = 0; i < line2 ; i++){
for (int j = 0; j < cow2; j++){
scanf("%d",&b[i][j]);
}
}


for (int i = 0; i < line1 ; i++){
for (int j = 0; j < cow2; j++){
for (int k = 0; k <line1; k++){
ans[i][j]+=a[i][k]*b[k][j];
}

printf("%d ",ans[i][j]);
}
puts(" ");
}

return 0;
}

在这里插入图片描述

4.定义有参无返函数实现杨慧三角
参数:二维数组,行,列

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

#include <stdio.h>

void YanhuiTri(int n){
int arr[n][n];
for (int i = 0; i < n; i++){
for (int j = 0; j <= i; j++){
if(j==0||i==j){
arr[i][j]=1;
}else{
arr[i][j]=arr[i-1][j]+arr[i-1][j-1];
}

printf("%-3d",arr[i][j]);

}
puts(" ");
}
}

int main(int argc, const char *argv[]){
int a;
scanf("%d",&a);

YanhuiTri(a);
return 0;
}

在这里插入图片描述

5.定义有参无返函数实现二维数组转置?
参数:二维数组,行,列

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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void Rev(int line,int row,int a[line][row]);
int main(int argc, const char *argv[]){
int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int line=sizeof(a)/sizeof(a[0]);
int row=sizeof(a[0])/sizeof(a[0][0]);
Rev(line,row,a);
return 0;
}

void Rev(int line,int row,int a[line][row]){
int b[row][line];
for(int i=0;i<line;i++){
for(int j=0;j<row;j++){
b[j][i]=a[i][j];
}
}

for(int i=0;i<row;i++){
for(int j=0;j<line;j++){
printf("%-3d",b[i][j]);
}
puts("");
}
}

在这里插入图片描述

6.输入一个字符串实现单词的逆置
eg:“good good study”
输出:“study good good”

7.输入n个字符串每个字符串20字节,并实现输出

D9.指针

C语言高级(2023/12/12~12/18)

数据结构(2023/12/18~12/23)

IO进程线程(2023/12/29~2024/10/2)

D1.IO基础

作业:

1> 使用fgets统计一个文件的行号

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
/*
* Filename: 01line.c
* Author: linus
* Date: 2023-12-29
* Version: 1.0
*
* Description: The purpose of this code.
*/

#include <stdio.h>

int main(int argc, const char *argv[]){
FILE *fp=NULL;
if(argc!=2){
puts("输入有误");
puts("eg:/a.out test.txt");
return -1;
}
if((fp=fopen(argv[1],"r"))==NULL){
perror("fopen error:");
return -1;
}

int line=0;
//char buff=0;

char buff[128];
while(NULL!=fgets(buff,sizeof(buff),fp)){
line++;
}

printf("此文件有%d行\n",line);
fclose(fp);
return 0;
}

2> 使用fgets、fputs完成两个文件的拷贝

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
/*
* Filename: 02cp.c
* Author: linus
* Date: 2023-12-29
* Version: 1.0
*
* Description: The purpose of this code.
*/

#include <stdio.h>

int main(int argc, const char *argv[]){
if(argc!=3){
puts("输入有误!");
return -1;
}
FILE* fp=NULL;
FILE*fp_cp=NULL;
if((fp=fopen(argv[1],"r"))==NULL){
perror("打开1文件出错:");
return -1;
}

if((fp_cp=fopen(argv[2],"w"))==NULL){
perror("打开2文件出错:");
return -1;
}

char buff[1024];
while(fgets(buff,sizeof(buff),fp)!=NULL){
fputs(buff,fp_cp);
}

puts("拷贝成功!");
fclose(fp);
fclose(fp_cp);
return 0;
}

3> 向文件中输出当前的系统时间

1
2
3
4
5
6
7
8
9
10
1、16:42:50
2、16:42:51
3、16:42:52
。。。
ctrl + C
./a.out
6、17:10:03
7、17:10:04
8、17:10:05
。。。
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
/*
* Filename: 03time.c
* Author: linus
* Date: 2023-12-29
* Version: 1.0
*
* Description: The purpose of this code.
*/

#include <stdio.h>
#include <time.h>
#include <unistd.h>

time_t sys_time = 0;
char time_buff[128] = ""; // 写入文件的字符串
struct tm *t;
int line = 1;

int get_time()
{
time(&sys_time);
t = localtime(&sys_time);
sprintf(time_buff, "%4d[%4d/%02d/%02d-%02d:%02d:%02d]\n", line,
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);

return t->tm_sec;
}

int main(int argc, const char *argv[])
{

FILE *fp = NULL;
int last_sec = -1;

if ((fp = fopen("./time.txt", "r")) == NULL)
{
perror("打开文件失败:");
// return -1;
}

// 先读出文件有多少行
char buff[128];
while (NULL != fgets(buff, sizeof(buff), fp))
{
line++;
}

while (1)
{
// a:以结尾写的形式打开文件,如果文件不存在,则创建文件,如果文件存在则结尾写,光标定位在开结尾
if ((fp = fopen("./time.txt", "a")) == NULL)
{
perror("打开文件失败:");
return -1;
}
sleep(1);

// 每秒才写入
if (last_sec != get_time())
{
last_sec = t->tm_sec;
fputs(time_buff, fp);
line++;
}
printf("%d\n", line);
fclose(fp);
}

return 0;
}

D2.IO基础

作业

1> 使用fread、fwrite完成两个文件的拷贝

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
/*
* Filename: 04freadcp.c
* Author: linus
* Date: 2024-01-02
* Version: 1.0
*
* Description: The purpose of this code.
*/
#include <stdio.h>

int main(int argc, const char *argv[])
{
//判断是否输错
if(argc!=3)
{
puts("输入错误!");
return -1;
}
//定义文件指针
FILE* fp=NULL;
FILE* fp_cp=NULL;

//打开文件
if((fp=fopen(argv[1],"r"))==NULL)
{
perror("fopen error:");
return -1;
}

if((fp_cp=fopen(argv[2],"w"))==NULL)
{
perror("fopen error:");
return -1;
}

char buff;

//循环遍历拷贝
while (1)
{
fread(&buff,1,sizeof(buff),fp);
fwrite(&buff,1,sizeof(buff),fp_cp);
if(feof(fp))
{
break;
}
}

//关闭文件
fclose(fp);
fclose(fp_cp);


return 0;
}

2> 将注册登录框架重新实现一遍

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
126
127
128
129
130
/*
* Filename: 09test.c
* Author: linus
* Date: 2024-01-02
* Version: 1.0
*
* Description: 重复使用菜单框架
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum Operate
{
REGISTER,
LOGIN,
EXIT
};
char *op_msg[] = {"注册", "登录", "退出"};

enum Operate menu;

int do_register()
{
FILE *wfp =NULL;
char username_reg[20];
char pwd_reg[20];

printf("请输入账号:");
fgets(username_reg,sizeof(username_reg),stdin);
printf("请输入密码:");
fgets(pwd_reg,sizeof(pwd_reg),stdin);

username_reg[strlen(username_reg)-1]='\0';
pwd_reg[strlen(pwd_reg)-1]='\0';

if((wfp=fopen("./user.txt","a+"))==NULL)
{
perror("open user.txt error:");
return -1;
}

fprintf(wfp,"%s %s\n",username_reg,pwd_reg);
fclose(wfp);
printf("注册成功!\n");

return 0;
}

int do_login()
{
FILE *wfp =NULL;
char input_username[20];
char input_pwd[20];

char username_reg[20];
char pwd_reg[20];

printf("请输入账号:");
fgets(input_username,sizeof(input_username),stdin);
printf("请输入密码:");
fgets(input_pwd,sizeof(input_pwd),stdin);

input_username[strlen(input_username)-1]='\0';
input_pwd[strlen(input_pwd)-1]='\0';

if((wfp=fopen("./user.txt","r"))==NULL)
{
perror("open user.txt error:");
return -1;
}

while(1)
{
int res = fscanf(wfp,"%s %s",username_reg,pwd_reg);
if (res<0)
{
printf("没有这个用户\n");
fclose(wfp);
return 1;
}

if(strcmp(username_reg,input_username)==0 && strcmp(pwd_reg,input_pwd)==0){
printf("登录成功!\n");
fclose(wfp);
return 0;
}

}

}

int main(int argc, const char *argv[])
{
while (1)
{
for (int i = 0; i <= EXIT; i++)
{
printf("【%d】:%s\t", i, op_msg[i]);
if ((i + 1) % 2 == 0)
{
puts("");
}
}
puts("");
printf("请输入要执行的操作:");
scanf("%d", &menu);
while (getchar() != '\n'); // 吸收非法字符
switch (menu)
{
case REGISTER:
do_register();
break;
case LOGIN:
do_login();
break;
case EXIT:
exit(EXIT_SUCCESS);
default:
printf("输入序号有误,请重新输入:");
}
printf("按任意键清屏\n");
while (getchar() != '\n'); // 吸收非法字符
system("clear");
}

return 0;
}

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
54
55
/*
* Filename: 05imgpr.c
* Author: linus
* Date: 2024-01-02
* Version: 1.0
*
* Description: The purpose of this code.
*/

#include <stdio.h>

int main(int argc, const char *argv[]){
FILE *fp=NULL;
if(NULL==(fp=fopen("./output.bmp","r+")))
{
perror("fopen error:");
return -1;
}

//向后偏移两个字节得到文件的大小
fseek(fp, 0x02, SEEK_SET);

unsigned int size;
fread(&size, sizeof(size), 1, fp); //从文件中读取一个整形数据
printf("size = %d\n", size);


unsigned int x,y;
//向后偏移两个字节得到分辨率的大小
fseek(fp, 0x12, SEEK_SET);
fread(&x, sizeof(size), 1, fp); //从文件中读取一个整形数据
fread(&y, sizeof(size), 1, fp); //从文件中读取一个整形数据
printf("x = %d\ny = %d\n", x,y);


//将光标偏移到图像数据处
fseek(fp, 54, SEEK_SET);

//想要更改像素
unsigned char color[3] = {255, 0, 0}; //纯蓝色

for(int i=0; i<800; i++) //外行
{
for(int j=0; j<33; j++) //内列
{
fwrite(color, sizeof(color), 1, fp);
}
}

//关闭文件
fclose(fp);

return 0;
}

面试题目

1.标准I0与文件IO的区别

标准IO依赖的是标准库,有缓冲区,效率高;文件IO依赖于系统调用,效率较低

2.什么是IO

input和output,IO就是程序对外部设备完成信息的交换过程

3.什么是文件指针?

指向文件的指针变量,可以通过这个变量来完成对文件的各种操作

4.简述一下系统调用

系统调用是用户空间程序与内核空间交互的一种方式,允许用户程序执行一些只有操作系统内核能够执行的特权操作。

5.如何判断一个单向链表中有环

遍历整个链表,判断某个结点是否被访问多次

D3.IO基础

作业

  1. 使用标准io完成两个文件的拷贝
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
#include <stdio.h>

int main(int argc, const char *argv[]){
if(argc!=3){
puts("输入有误!");
return -1;
}
FILE* fp=NULL;
FILE*fp_cp=NULL;
if((fp=fopen(argv[1],"r"))==NULL){
perror("打开1文件出错:");
return -1;
}

if((fp_cp=fopen(argv[2],"w"))==NULL){
perror("打开2文件出错:");
return -1;
}

char buff[1024];
while(fgets(buff,sizeof(buff),fp)!=NULL){
fputs(buff,fp_cp);
}

puts("拷贝成功!");
fclose(fp);
fclose(fp_cp);
return 0;
}
  1. 使用文件IO完成两个文件的拷贝
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
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
if(argc!=3)
{
puts("输入有误");
return -1;
}
int fd=-1,fd_cp=-1;
fd=open(argv[1],O_RDONLY);
if(fd==-1)
{
perror("打开文件1失败:");
return -1;
}
fd_cp=open(argv[2],O_WRONLY | O_CREAT | O_TRUNC,0664);
if(fd_cp==-1)
{
perror("打开文件2失败:");
return -1;
}

// ssize_t write(int fd, const void *buf, size_t count);
// 功能:将buf指向的地址中count个字节,写入到fd指向的文件中
// 参数1:文件描述符
// 参数2:容器起始地址,void*类型,表明可以写入任何类型的数据
// 参数3:要写入数据的个数
// 返回值:成功返回写入的字符个数,失败返回-1并置位错误码

// ssize_t read(int fd, void *buf, size_t count);
// 功 能:从fd文件中,将count个字节读取到buf对应的容器中
// 参数1:文件描述符
// 参数2:容器起始地址,void*类型,表明可以读取任何类型的数据
// 参数3:要读取数据的个数
// 返回值:成功返回读取字节的个数,失败返回-1并置位错误码

//循环写入
char buff[4096];
int res;
while((res=read(fd,buff,sizeof(buff)))>0)
{
write(fd_cp,buff,res);
}
//关闭文件
close(fd);
close(fd_cp);
}
  1. 将stat函数实现一遍
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
#include<myhead.h>

int main(int argc, const char *argv[])
{
//定义文件属性类型的数据
struct stat sb; //用于存储获得的文件属性

//调用函数的到文件属性
stat(argv[1], &sb);

switch(sb.st_mode&S_IFMT)
{
case S_IFSOCK:
{
printf("这是套接字文件\t");
}
break;
case S_IFLNK:
{
printf("这是链接文件\t");
}
break;
case S_IFREG:
{
printf("这是普通文件\t");
}
break;
case S_IFBLK:
{
printf("这是块设备文件\t");
}
break;
case S_IFDIR:
{
printf("这是目录文件\t");
}
break;
case S_IFCHR:
{
printf("这是字符设备文件\t");
}
break;
case S_IFIFO:
{
printf("这是管道文件\t");
}
break;

}

printf("%#o\t%ld\t%ld\n", sb.st_mode&0777, sb.st_size, sb.st_ino);

return 0;
}

  1. 将目录操作实现一遍
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
#include<myhead.h>

int main(int argc, const char *argv[])
{
//判断外部传参个数
if(argc != 2)
{
printf("input error\n");
printf("usage:./a.out name\n");
return -1;
}

//定义目录指针
DIR *dp = NULL;
//打开目录
if((dp = opendir(argv[1])) == NULL)
{
perror("opendir error");
return -1;
}

//读取目录中的文件或目录信息
struct dirent *sdp = NULL;
while((sdp = readdir(dp)) != NULL)
{
//输出当前文件或目录的信息
printf("inode:%10ld, size:%10d, %10s, ",\
sdp->d_ino, sdp->d_reclen, sdp->d_name);

//输出类型
switch(sdp->d_type)
{
case DT_BLK:
{
printf("b\n");
}
break;
case DT_CHR:
{
printf("c\n");
}
break;

case DT_DIR:
{
printf("d\n");
}
break;

case DT_FIFO:
{
printf("p\n");
}
break;
case DT_LNK:
{
printf("l\n");
}
break;
case DT_REG:
{
printf("-\n");
}
break;
case DT_SOCK:
{
printf("s\n");
}
break;
}
}





//关闭目录
closedir(dp);

return 0;
}

D4.进程线程基础

作业

1> 创建出三个进程完成两个文件之间拷贝工作,子进程1拷贝前一半内容,子进程2拷贝后一半内容,父进程回收子进程的资源

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
/*
* Filename: errno.c
* Author: linus
* Date: 2023-12-29
* Version: 1.0
*
* Description: 创建出三个进程完成两个文件之间拷贝工作,
* 子进程1拷贝前一半内容,子进程2拷贝后一半内容,
* 父进程回收子进程的资源
*/

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
// 判断输入是否正确
if (argc != 3)
{
puts("输入有误!");
return -1;
}
// 定义文件指针
FILE *fp = 0;
FILE *fp_cp = 0;
// 以只读的形式打开文件
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("fopen:");
return -1;
}

// 以只写的形式打开文件
if ((fp_cp = fopen(argv[2], "w")) == NULL)
{
perror("fopen:");
return -1;
}

// 读文件大小
fseek(fp, 0, SEEK_END);
long file_size = ftell(fp);
long half_size = file_size / 2;
rewind(fp);

// 创建出一个子进程
pid_t pid1 = fork();
if (pid1 == 0) // 子进程1
{
char buff;
while (ftell(fp) < half_size)
{
int res = fread(&buff, 1, sizeof(buff), fp);
fwrite(&buff, 1, res, fp_cp);
}

exit(EXIT_SUCCESS);
}
else if (pid1 == -1)
{
perror("fork error");
return -1;
}

// 创建出另一个子进程
pid_t pid2 = fork();
if (pid2 == 0) // 子进程2
{
sleep(1);
char buff;
fseek(fp, half_size, SEEK_SET);
fseek(fp_cp, half_size, SEEK_SET);
while (!feof(fp))
{
int res = fread(&buff, 1, sizeof(buff), fp);
fwrite(&buff, 1, res, fp_cp);
}
exit(EXIT_SUCCESS);
}
else if (pid1 == -1)
{
perror("fork error");
return -1;
}

wait(NULL);
wait(NULL);

fclose(fp);
fclose(fp_cp);

return 0;
}

D5.进程线程通信

作业:

1> 将互斥机制代码重新实现一遍

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
/*
* Filename: 1.c
* Author: linus
* Date: 2024-01-05
* Version: 1.0
*
* Description: 互斥机制
*/

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <pthread.h>
#include <string.h>

//创建一个互斥锁
pthread_mutex_t mutex;

void* task(void *arg)
{
while (1)
{
pthread_mutex_lock(&mutex);

printf("子线程");

pthread_mutex_unlock(&mutex);
}


}

int main(int argc, const char *argv[])
{
//定义线程号变量
pthread_t tid;

//初始化互斥锁
pthread_mutex_init(&mutex, NULL);

if(pthread_create(&tid,NULL,task,NULL)!=0)
{
perror("tid create error\n");
return -1;
}

while (1)
{
//获取锁资源
pthread_mutex_lock(&mutex);

printf("主线程\n");

//释放锁资源
pthread_mutex_unlock(&mutex);
}




return 0;
}


2> 将同步机制代码重新实现一遍

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
/*
* Filename: 2.c
* Author: linus
* Date: 2024-01-05
* Version: 1.0
*
* Description: The purpose of this code.
*/

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>

sem_t sem;

void* task1(void* arg)
{
while(1)
{
sem_post(&sem);
printf("post了sem\n");
sleep(2);
}
pthread_exit(NULL);
}

void* task2(void* arg)
{
while(1)
{
sem_wait(&sem);
printf("收到了\n");

}

pthread_exit(NULL);
}

int main(int argc, const char *argv[])
{
pthread_t tid1,tid2;

sem_init(&sem,0,0);

if((pthread_create(&tid1,NULL,task1,NULL))!=0)
{
perror("thread creat error");
return -1;
}
if((pthread_create(&tid2,NULL,task2,NULL))!=0)
{
perror("thread creat error");
return -1;
}

pthread_join(tid1,NULL);
pthread_join(tid2,NULL);

return 0;
}

3> 使用三个线程完成两个文件的拷贝,线程1完成拷贝前一半,线程2完成拷贝后一半,主线程回收两个分支线程的资源

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
/*
* Filename: 3.c
* Author: linus
* Date: 2024-01-05
* Version: 1.0
*
* Description: 使用三个线程完成两个文件的拷贝,
* 线程1完成拷贝前一半,线程2完成拷贝后一半,
* 主线程回收两个分支线程的资源
*/

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>

sem_t sem;
int len,half_hen;
const char *srcFile,*destFile;

int file_len(const char *file)
{
FILE* fp=NULL;
if((fp=(fopen(file,"r")))==NULL)
{
perror("open fire error");
return -1;
}
fseek(fp,0,SEEK_END);
return ftell(fp);
}

int copy_file(const char *srcFile, const char *destFile, int begin, int end)
{
FILE* srcfp=NULL;
FILE* destfp=NULL;
if ((srcfp=(fopen(srcFile, "r"))) == NULL)
{
perror("open srcFile error");
return -1;
}
if ((destfp=(fopen(destFile, "w"))) == NULL)
{
perror("open destFile error");
return -1;
}

fseek(destfp,begin,SEEK_SET);
fseek(srcfp,begin,SEEK_SET);
char buff;
while(ftell(srcfp)<end)
{
int res=fread(&buff,1,sizeof(buff),srcfp);
fwrite(&buff,1,res,destfp);
}
fclose(srcfp);
fclose(destfp);
return 0;
}

void *task1(void *arg)
{
copy_file(srcFile,destFile,0,half_hen);
pthread_exit(NULL);
}

void *task2(void *arg)
{
copy_file(srcFile,destFile,half_hen,len);
pthread_exit(NULL);

}

int main(int argc, const char *argv[])
{
if(argc!=3)
{
printf("输入有误!\n");
return -1;
}


srcFile=argv[1];
destFile=argv[2];

len=file_len(argv[1]);
half_hen=len/2;
pthread_t tid1, tid2;

if ((pthread_create(&tid1, NULL, task1, NULL)) != 0)
{
perror("thread creat error");
return -1;
}
if ((pthread_create(&tid2, NULL, task2, NULL)) != 0)
{
perror("thread creat error");
return -1;
}


pthread_join(tid1, NULL);
pthread_join(tid2, NULL);

return 0;
}

4> 使用三个线程完成:线程1输出字符’A’,线程2输出字符’B’,线程3输出字符’C’,要求输出结果为:ABCABCABCABCABC…

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
/*
* Filename: 4.c
* Author: linus
* Date: 2024-01-05
* Version: 1.0
*
* Description: 使用三个线程完成:线程1输出字符’A’,线程2输出字符’B’,
* 线程3输出字符’C’,
* 要求输出结果为:
* ABCABCABCABCABC…
* 思路:使用三个互斥信号量来实现排队输出
*/

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>

sem_t sem1,sem2,sem3;

void* task1(void *arg)
{
while (1)
{
sem_wait(&sem2);
printf("B");
fflush(stdout);//遇到的坑,没有刷新缓存区
sem_post(&sem3);
}
}

void* task2(void *arg)
{
while (1)
{
sem_wait(&sem3);
printf("C");
fflush(stdout);
sem_post(&sem1);
}
}

int main(int argc, const char *argv[])
{
// 初始化匿名信号量
sem_init(&sem1,0,1);
sem_init(&sem2,0,0);
sem_init(&sem2,0,0);
// 创建两个线程
pthread_t tid1, tid2;

if ((pthread_create(&tid1, NULL, task1, NULL)) != 0)
{
perror("thread creat error");
return -1;
}
if ((pthread_create(&tid2, NULL, task2, NULL)) != 0)
{
perror("thread creat error");
return -1;
}
printf("线程创建成功\n");

// 主线程

while (1)
{
sem_wait(&sem1);
printf("A");
fflush(stdout);
sem_post(&sem2);
sleep(1);
}
// 释放线程
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}


实现结果

5> 周末完成C语言基础测试题
没写完,哈哈

D6.进程线程通信

作业

1> 使用有名管道完成两个进程之间相互通信
在这里插入图片描述

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
126
127
128
129
130
131
132
133
134
135
136
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <pthread.h>
#include <string.h>

// 创建两个管道文件描述符
int rfd = -1;
int wfd = -1;
int userid = 0;

void *receive(void *arg)
{
char rbuf[128] = "";
while (1)
{
bzero(rbuf, sizeof(rbuf)); // 清空内容
// 从管道中读取数据
read(rfd, rbuf, sizeof(rbuf));
printf("*******新消息*******\n");
printf("\n%s\n\n", rbuf);
printf("请输入回复内容:\n");

// 判断
if (strcmp(rbuf, "quit") == 0)
{
break;
}
}
close(rfd);
pthread_exit(NULL);
}

void *send(void *arg)
{
char wbuf[128] = "";
while (1)
{
bzero(wbuf, sizeof(wbuf)); // 清空内容
// 从终端输入数据
fflush(stdout); // 刷新行缓冲区
read(0, wbuf, sizeof(wbuf));
wbuf[strlen(wbuf) - 1] = 0; // 将回车换成'\0'

// 将数据写入管道中
write(wfd, wbuf, sizeof(wbuf));
// 判断
if (strcmp(wbuf, "quit") == 0)
{
break;
}
}
close(wfd);
pthread_exit(NULL);
}

int main(int argc, const char *argv[])
{
// 创建有名管道文件
// if (mkfifo("./fifo1", 0664) != 0)
// {
// perror("mkfifo error");
// return -1;
// }
// // 创建有名管道文件
// if (mkfifo("./fifo2", 0664) != 0)
// {
// perror("mkfifo error");
// return -1;
// }
printf("myfifo create success\n");

printf("写端打开成功\n");
printf("请输入用户ID:");
scanf("%d", &userid);
printf("等待其他用户上线。\n");
switch (userid)
{
case 1:
if ((wfd = open("./fifo1", O_WRONLY)) == -1)
{
perror("open error");
return -1;
}
if ((rfd = open("./fifo2", O_RDONLY)) == -1)
{
perror("open error");
return -1;
}

break;
case 2:
if ((rfd = open("./fifo1", O_RDONLY)) == -1)
{
perror("open error");
return -1;
}
if ((wfd = open("./fifo2", O_WRONLY)) == -1)
{
perror("open error");
return -1;
}
break;
default:
break;
}

system("clear");

printf("fifo create success\n");

pthread_t tid1, tid2;

if (pthread_create(&tid1, NULL, receive, NULL) != 0)
{
printf("tid1 creat error\n");
return -1;
}

if (pthread_create(&tid2, NULL, send, NULL) != 0)
{
printf("tid1 creat error\n");
return -1;
}

printf("线程创建成功!\n");

pthread_join(tid1, NULL);
pthread_join(tid2, NULL);

return 0;
}

在这里插入图片描述

D7.进程线程通信

思维导图
思维导图

作业
1> 使用消息队列完成两个进程之间相互通信

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
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int userid = 0;

char username1[128];
char username2[128];

// 定义消息结构体类型
struct message
{
long mtype; // 消息类型
char mtext[4096]; // 消息正文
};

// 1、创建key值
key_t key = 0;
// 2、使用key值创建一个消息队列
int msgid = 0;

// 定义一个宏,表示正文大小
#define SIZE (sizeof(struct msgbuf) - sizeof(long))

// 此时就已经在内核空间创建出消息队列了


// 发送消息的函数
void send_message(int msgid, long mtype, const char *sender, const char *receiver)
{
struct message msg;
msg.mtype = mtype;
printf("[%s] Enter a message for %s: ", sender, receiver);
fgets(msg.mtext, sizeof(msg.mtext), stdin);

// 发送消息
if (msgsnd(msgid, &msg, sizeof(msg.mtext), 0) == -1)
{
perror("msgsnd");
exit(EXIT_FAILURE);
}
}

// 接收消息的函数
void receive_message(int msgid, long mtype, const char *receiver)
{
struct message msg;

// 接收消息
if (msgrcv(msgid, &msg, sizeof(msg.mtext), mtype, 0) == -1)
{
perror("msgrcv");
exit(EXIT_FAILURE);
}

// 打印接收到的消息
printf("[%s] Received message: %s\n", receiver, msg.mtext);
}

void *receive(void *arg)
{
// 3、循环向消息队列中存放数据
while (1)
{
receive_message(msgid, 2, username1);
}
}

void *send(void *arg)
{
send_message(msgid, 1, username1, username2);
}

int main(int argc, const char *argv[])
{
if ((key = ftok("/", 'a')) == -1)
{
perror("fork error");
return -1;
}

if ((msgid = msgget(key, IPC_CREAT | 0664)) == -1)
{
perror("msgget error");
return -1;
}

printf("请输入您的用户名:");
fgets(username1,sizeof(username1), stdin);

// printf("等待其他用户上线。\n");
printf("请输入对方的用户名:");
fgets(username2,sizeof(username2), stdin);
pthread_t tid1, tid2;

if (pthread_create(&tid1, NULL, receive, NULL) != 0)
{
printf("tid1 creat error\n");
return -1;
}

if (pthread_create(&tid2, NULL, send, NULL) != 0)
{
printf("tid1 creat error\n");
return -1;
}

printf("线程创建成功!\n");

pthread_join(tid1, NULL);
pthread_join(tid2, NULL);

return 0;
}

2> 将信号通信相关代码重新实现一遍

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
#include<myhead.h>

//定义信号处理函数
void handler(int signum)
{
if(signum == SIGINT) //表明要处理2号信号
{
printf("用户按下了ctrl + c键\n");
}

if(signum == SIGTSTP) //处理暂停信号
{

printf("用户按下了ctrl + z键\n");
}
}

/****************************主程序********************/
int main(int argc, const char *argv[])
{

/*将SIGINT信号忽略
if(signal(SIGINT, SIG_IGN) == SIG_ERR)
{
perror("signal error");
return -1;
}
*/

/*将SIGINT信号默认处理
if(signal(SIGINT, SIG_DFL) == SIG_ERR)
{
perror("signal error");
return -1;
}
*/

//将SIGINT信号捕获
if(signal(SIGINT, handler) == SIG_ERR)
{
perror("signal error");
return -1;
}

//绑定SIGTSTP信号 ctrl + z
if(signal(SIGTSTP, handler) == SIG_ERR)
{
perror("signal error");
return -1;
}



while(1)
{
sleep(1);
printf("我真的还想再活五百年\n");
}

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
58
59
60
#include<myhead.h>

//定义信号处理函数
void handler(int signum)
{
if(signum == SIGINT) //表明要处理2号信号
{
printf("用户按下了ctrl + c键\n");
}

if(signum == SIGTSTP) //处理暂停信号
{

printf("用户按下了ctrl + z键\n");
}


if(signum == SIGSTOP) //处理暂停信号
{

printf("用户按下了ctrl + z键\n");
}
}

/****************************主程序********************/
int main(int argc, const char *argv[])
{
/*尝试忽略SIGSTOP信号
if(signal(SIGSTOP, SIG_IGN) == SIG_ERR)
{
perror("signal error");
return -1;
}
*/

/*尝试捕获SIGSTOP信号
if(signal(SIGSTOP, handler) == SIG_ERR)
{
perror("signal error");
return -1;
}
*/

//尝试默认处理SIGSTOP信号
if(signal(SIGSTOP, SIG_DFL) == SIG_ERR)
{
perror("signal error");
return -1;
}

while(1)
{
sleep(1);
printf("我真的还想再活五百年\n");
}

return 0;
}


3> 将共享内存相关代码重新实现一遍

1> 发送端

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
#include<myhead.h>
#define PAGE_SIZE 4096

int main(int argc, const char *argv[])
{
//1、创建key值
key_t key = -1;
if((key = ftok("/", 't')) == -1)
{
perror("ftok error");
return -1;
}
printf("key = %#x\n", key);

//2、将物理内存创建出共享内存段
int shmid = 0;
if((shmid = shmget(key, PAGE_SIZE, IPC_CREAT|0664)) == -1)
{
perror("shmget error");
return -1;
}
printf("shmid = %d\n", shmid);

//3、将共享内存段地址映射到用户空间
//NULL表示让系统自动选择页的分段
//0表示当前进程对共享内存具有读写功能
char *addr = (char *)shmat(shmid, NULL, 0);
if(addr == (void *)-1)
{
perror("shmat error");
return -1;
}
printf("addr = %p\n", addr);

//4、操作共享内存
//char buf[128] = "";
while(1)
{
fgets(addr, PAGE_SIZE, stdin); //从终端输入数据
addr[strlen(addr) - 1] = '\0'; //将换行换成'\0'

if(strcmp(addr, "quit") == 0)
{
break;
}
}


//5、取消映射

while(1);

return 0;
}

2> 接收端

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
#include<myhead.h>
#define PAGE_SIZE 4096

int main(int argc, const char *argv[])
{
//1、创建key值
key_t key = -1;
if((key = ftok("/", 't')) == -1)
{
perror("ftok error");
return -1;
}
printf("key = %#x\n", key);

//2、将物理内存创建出共享内存段
int shmid = 0;
if((shmid = shmget(key, PAGE_SIZE, IPC_CREAT|0664)) == -1)
{
perror("shmget error");
return -1;
}
printf("shmid = %d\n", shmid);

//3、将共享内存段地址映射到用户空间
//NULL表示让系统自动选择页的分段
//0表示当前进程对共享内存具有读写功能
char *addr = (char *)shmat(shmid, NULL, 0);
if(addr == (void *)-1)
{
perror("shmat error");
return -1;
}
printf("addr = %p\n", addr);

//4、操作共享内存
//char buf[128] = "";
while(1)
{

printf("共享内存中的数据为:%s\n", addr);
sleep(1);

if(strcmp(addr, "quit") == 0)
{
break;
}
}


//5、取消映射
if(shmdt(addr) == -1)
{
perror("shmdt error");
return -1;
}


//6、删除共享内存
if(shmctl(shmid, IPC_RMID, NULL) == -1)
{
perror("shmctl error");
return -1;
}

return 0;
}

D8. 信号量(信号灯集)&库的制作

作业

使用信号灯集完成三个进程的同步,A进程输出字符A,B进程输出字符B,C进程输出字符C,要求输出结果为ABCABCABCABCABC…

网络通信基础(2024/01/12~01/22)

网络通信基础思维导图
网络通信基础思维导图

D1.发展史&TCP/IP

D2.TCP和UDP基础通信模型

D3.

D4.多点通信&域套接字

作业

1> 将广播、组播、流式域套接字、报式域套接字各实现一遍

2> 完成TFTP文件传输作业

D5.IO模型分类

作业

1> 使用select实现TCP客户端的并发

2> 使用poll实现TCP服务器的并发

D6&D7.数据库

C++&QT(2024/01/24~NOW)

D1.C++基础

提示并输入一个字符串,统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数
要求使用C++风格字符串完成

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
#include <iostream>

// 提示并输入一个字符串,统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数
// 要求使用C++风格字符串完成

using namespace std;

int main()
{
string str;
cout << "请输入一个字符串:";
getline(cin, str); // 包含空格输入
// 初始化计数变量
int uppercaseCount = 0;
int lowercaseCount = 0;
int digitCount = 0;
int spaceCount = 0;
int otherCount = 0;
for (char ch : str)
{
if (isupper(ch))
uppercaseCount++;
else if (islower(ch))
lowercaseCount++;
else if (isdigit(ch))
digitCount++;
else if (isspace(ch))
spaceCount++;
else
otherCount++;
}

cout << "大写:" << uppercaseCount << endl;
cout << "小写:" << lowercaseCount << endl;
cout << "数字:" << digitCount << endl;
cout << "空格:" << spaceCount << endl;
cout << "其他:" << otherCount << endl;

return 0;
}

D2&D3.C++基础

作业:

设计一个Per类,类中包含私有成员:姓名、年龄、指针成员身高、体重,再设计一个Stu类,类中包含私有成员:成绩、Per类对象p1,设计这两个类的构造函数、析构函数和拷贝构造函数。