c语言,shell指令,数据结构,文件io,C++基础习题

C语言

6.10 .

使用switch实现银行系统,默认用户为A,密码为1234,余额2000如果登录失败,则直接结束
如果登录成功,则显示银行页面
1.查询余额
2.取钱
3.存钱
如果是1,则打印余额如果是2,则输入取钱金额,如果金额大于存款则输出余额不足,否则输出剩余金钱如果是3,则输入存款金额,输出存款后的金额

 3.输入一个表达式,实现计算器+-*/%
例如:1+2,则输出35/2,则输出2.5

练习4:下面代码执行后,a\b\c的结果是?
int a=5,b=7,c;
c=a+++b;

 解:c=12

c = a++ + b;a先赋值后加加故c=5+7;

练习5:代码如下
void main()
{
int c=9,d=0;
C=C++%5;
d=c;
printf("d=%d\n",d);

}

解:d=4;

练习6.给定一个整数,判断它是否被3、5、7整除,并输出一下信息(笔试)
1.能同时被3,5,7整除(直接输出357,每个数字之间一个空格)
2.只能内其中两个整数整除(输出两个数,小的在前,大的在后,例如35 或者 37 或者57,中间使用空格隔开
3.只能被其中一个整数整除(输出这个除数)
4.不能被任何数整除,输出小写字母
案例如下:
输入:105
输出:357

#include <stdio.h>

int main() {
    int num;
    
    printf("请输入一个整数: ");
    scanf("%d", &num);
    
    if (num % 3 == 0 && num % 5 == 0 && num % 7 == 0) {
        printf("3 5 7\n");
    } else if (num % 3 == 0 && num % 5 == 0) {
        printf("3 5\n");
    } else if (num % 3 == 0 && num % 7 == 0) {
        printf("3 7\n");
    } else if (num % 5 == 0 && num % 7 == 0) {
        printf("5 7\n");
    } else if (num % 3 == 0) {
        printf("3\n");
    } else if (num % 5 == 0) {
        printf("5\n");
    } else if (num % 7 == 0) {
        printf("7\n");
    } else {
        printf("n\n");
    }
    
    return 0;
}

 练习7:

 a=10;b=10;c=12=a;

d=10*12=120;a=13;

find:b=10;c=12;d=120;

练习8:

c=-75;a=181;d=6;e=5;

练习9:

b:0000 0110 ----> 0001 1000

                              a:0000 0011

                            ^-----------------

                                 0001 1011

6.11

1.计算公约数,公倍数

#include <stdio.h>

// 使用欧几里得算法计算最大公约数
int gcd(int a, int b)
{
    if (b == 0)
    {
        return a;
    }
    return gcd(b, a % b);
}

// 计算最小公倍数
int lcm(int a, int b)
{
    return (a * b) / gcd(a, b);
}

int main()
{
    printf("输入两个数,计算最大公约数,以及最小公倍数--------------------------\n");

    int a, b;
    printf("请输入两个正整数:");

    // 检查输入是否正确
    if (scanf("%d %d", &a, &b) != 2 || a <= 0 || b <= 0)
    {
        printf("输入错误,请确保输入两个正整数。\n");
        return 1; // 退出程序
    }

    // 计算最大公约数和最小公倍数
    int temp1 = gcd(a, b);
    int temp2 = lcm(a, b);

    printf("最大公约数是:%d\n", temp1);
    if (temp1 == 1)
    {
        printf("没有最大公约数\n");
    }
    else
    {
        printf("最小公倍数是:%d\n", temp2);
    }

    return 0;
}

2.各类小题目合集

#include <myhead.h>
void loop1()
{
    printf("求一定范围内的偶数和-------------------------------------\n");
    int num = 0;
    int max = 0;
    int sum = 0;
    printf("请输入循环最大值:");
    scanf("%d", &max);
    do
    {
        if (num % 2 == 0)
        {
            sum += num;
        }
        num++;
    } while (num <= max);
    printf("所有偶数和为%d\n", sum);
}
void loop2()
{
    printf("求一定范围内的总数和-------------------------------------------\n");
    int sum = 0;
    int num = 0;
    printf("请输入值:\n");
    do
    {

        scanf("%d", &num);
        sum += num;
    } while (num);
    printf("总和为%d\n", sum);
}
void loop3()
{
    printf("输入用户密码判读对错-------------------------------------------\n");
    char user = 'A', take_user = 0;
    int key = 1234, take_key = 0;
    int count = 1;
    do
    {
        take_key = 0;
        take_user = 0;
        printf("请输入用户名和密码:\n");
        scanf("%c%d", &take_user, &take_key);
        getchar();
        if (user == take_user && key == take_key)
        {
            printf("登录成功\n");
            break;
        }
        else
        {
            printf("用户名或密码错误,请重新输入\n");
            printf("第%d次登录失败,还剩%d次机会\n", count, 3 - count);
            count++;
        }
    } while (count <= 3);
    if (count >= 3)
    {
        printf("账户被锁\n");
    }
}
void loop4()
{
    printf("求n的阶乘--------------------------------------\n");
    int count, sum = 1;
    scanf("%d", &count);
    for (int i = 1; i <= count; i++)
    {
        sum *= i;
    }
    printf("%d\n", sum);
}
void loop5()
{
    printf("求斐波那契数列各项-------------------------------\n");
    int num, num1 = 1, num2 = 1, num3 = 0;
    printf("请输入要求的斐波那契额数列项数:");
    scanf("%d", &num);
    if (num <= 2)
    {
        for (int i = 0; i < num; i++)
        {
            printf("1 ");
        }
    }
    else
    {
        printf("1 1 ");
        for (int i = 3; i <= num; i++)
        {
            num3 = num1 + num2;
            printf("%d ", num3);
            num1 = num2;
            num2 = num3;
        }
        printf("\n");
    }
}
void loop6()
{
    printf("用for打印1~5--------------------------\n");
    int i = 0;
start:
    if (i > 5)
    {
        return 0;
    }
    printf("%d ", i);
    i++;
    goto start;
}
void loop7()
{
    printf("打印三行五列*--------------------------\n");

    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            printf("* ");
        }
        printf("\n");
    }
}
void loop8()
{
    printf("打印三角*--------------------------\n");

    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            if (j <= i)
            {
                printf("* ");
            }
        }
        printf("\n");
    }
}
void loop9()
{
    printf("打印三角*--------------------------\n");

    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            if (i <= j)
            {
                printf("* ");
            }
        }
        printf("\n");
    }
}
void loop10()
{
    printf("打印三角*--------------------------\n");
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            if (j + i >= 3)
            {
                printf("* ");
            }
            else
            {
                printf("  ");
            }
        }
        printf("\n");
    }
}
void loop11()
{
    printf("打印三角*--------------------------\n");
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            if (j >= i)
            {
                printf("*");
            }
            else
            {
                printf(" ");
            }
        }
        printf("\n");
    }
}
void loop13()
{
    printf("输入一个数,判断是否为素数-----------------------------------------\n");
    int a;
    printf("请输入一个数:");
    scanf("%d", &a);
    int i;
    for (i = 2; i < a; i++)
    {
        if (a % i == 0)
        {
            printf("不是素数\n");
            break;
        }
    }
        printf("是素数\n");
}
int main(int argc, const char *argv[])
{
     loop1();
     loop2();
     loop3();
     loop4();
     loop5();
     loop6();
     loop7();
     loop8();
     loop9();
     loop10();
     loop11();
     loop13();
    return 0;

6.12 

 小例题:

#include <myhead.h>
void arr_test1()
{
    printf("数组训练循环输入输出求和-----------------------------\n");
    float arr[5] = {0};
    float sum_vale = 0;
    for (int i = 0; i < 5; i++)
    {
        printf("请输入第%d个数字:", i + 1);
        scanf("%f", &arr[i]);
    }
    for (int i = 0; i < 5; i++)
    {
        printf("%f\n", arr[i]);
    }
    for (int i = 0; i < 5; i++)
    {
        sum_vale += arr[i];
    }
    printf("平均值为%.2f\n", sum_vale / 5);
}

void arr_test2()
{
    /* 初始化数组和最大最小值变量 */
    printf("求数组最大最小值-----------------------------\n");
    int arr[5] = {0};
    int max = 0;
    int min = 0;

    /* 通过用户输入填充数组 */
    for (int i = 0; i < 5; i++)
    {
        printf("请输入第%d个数字:", i + 1);
        scanf("%d", &arr[i]);
    }

    /* 使用数组的第一个元素作为初始最大最小值 */
    max = arr[0];
    min = arr[0];

    /* 遍历数组以更新最大最小值 */
    for (int i = 0; i < 5; i++)
    {
        if (arr[i] > max)
        {
            max = arr[i]; // 比当前值大就赋值,得最大
        }
        if (arr[i] < min)
        {
            min = arr[i]; // 比当前值小就赋值,得最小
        }
    }

    /* 输出最大和最小值 */
    printf("最大值为%d,最小值为%d\n", max, min);
}
void arr_test3()
{
    printf("数组的冒泡排序-----------------------------\n");
    /* 初始化一个长度为10的整型数组,用于存储用户输入的数字 */
    int arr[10] = {0};
    for (int i = 0; i < 10; i++)
    {
        /* 提示用户输入第i+1个数字 */
        printf("请输入第%d个数字:", i + 1);
        /* 从标准输入读取一个整型数字,存储到数组的第i个位置 */
        scanf("%d", &arr[i]);
    }

    /* 使用temp变量作为临时存储,用于交换数组中的元素 */
    int temp = arr[0];
    /* 外层循环控制比较的轮数,每轮找到一个最大值 */
    for (int i = 0; i < 10; i++)
    {
        /* 内层循环控制每轮比较的次数,每次比较相邻的两个元素 */
        for (int j = i + 1; j < 10; j++)
        {
            /* 如果当前元素大于后续元素,则交换它们的位置 ,以下方法先确定最小值*/
            if (arr[i] > arr[j])
            {
                temp = arr[i];   /* 先将当前元素存储到temp中 */
                arr[i] = arr[j]; /* 将后续元素赋值给当前元素 */
                arr[j] = temp;   /* 将temp中的值赋给后续元素 */
            }
        }
    }
    printf("从小到大排序:");
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}
void arr_test4()
{
    printf("二维数组的输入输出和平均值-----------------------------\n");
    int arr[2][3] = {0};
    int sum = 0;
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("请输入第%d行第%d列的数字:", i + 1, j + 1);
            scanf("%d", &arr[i][j]);
        }
    }
    // 二维输出
    //  for (int i = 0; i < 2; i++)
    //  {
    //      for (int j = 0; j < 3; j++)
    //      {
    //          sum += arr[i][j];
    //          printf("%d ",arr[i][j]);
    //      }
    //      printf("\n");
    //  }
    for (int i = 0; i < 2 * 3; i++) // 一维输出
    {

        sum += arr[0][i];
        printf("%d ", arr[0][i]);
    }
    int len = sizeof(arr) / sizeof(arr[0][0]);
    printf("平均值为%.2f\n", (float)sum / len);
}
void arr_test5()
{
    printf("二维数组的输入输出和最大最小值-----------------------------\n");
    int arr[][4] = {12, 4, 3, 5, 7, 2, 5};
    int max = arr[0][0];
    int min = arr[0][0];
    for (int i = 0; i < 8; i++)
    {
        if (max < arr[0][i])
        {
            max = arr[0][i];
        }
        if (min > arr[0][i])
        {
            min = arr[0][i];
        }
    }
    printf("最大值为%d,最小值为%d\n", max, min);
}

int main(int argc, char *argv[])
{
    arr_test1();
    arr_test2();
    arr_test3();
    arr_test4();
    arr_test5();

    return 0;
}

6.13

1.杨辉三角问题

2.差值问题 

3.查找第二大值问题 

输入一个m行n列的二维数组,计算第二大值;

4.元素出现次数问题

输入n个元素的一维数组,输入查找的key值

如果key出现一次,则输出对应的下表

如果key没有出现,则提示不存在

如果key出现多次,则提示出现的次数

 5.求数组行列和问题

.输入一个m行n列的二维数组,输出每一行的和,以及每一列的和

 .输入一个m行m列的二维数组,输出正对角线和反对角线的差

 6.数组行列转换问题

输入一个2行3列的二维数组,请实现转置(行列转换)

#include <stdio.h>
void arr_test12()
{
    printf("输入一个2行3列的二维数组,请实现转置(行列转换)-----------\n");
    int m=2, n=3;
    int arr[m][n];
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
            printf("请输入第%d行第%d列的数字:", i + 1, j + 1);
            scanf("%d", &arr[i][j]);
        }
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            printf("%d ", arr[j][i]);
        }
        printf("\n");
    }
}

 7.填空:

#include <myhead.h>
#define MOD(x, y) x % y
int main(int argc, const char *argv[])
{
    float a = 2, b = 4, c = 3;
    printf("%f\n", (1 / 2) + (a + b) * c);//18
    int x = 'f';
    printf("%c\n", 'a' + (x - 'a' + 1));//g
    int k = 7 >> 1;
    printf("%d\n", k);//3
    int a1 = 10, b1 = 94;
    printf("%d\n", MOD(b1, a1 + 4));//8
    int a2 = 1, b2 = 2, x2 = 0;
    if (!(--a2))
        x2--;
    if (!b2)
        x2 = 7;
    else
        ++x2;
    printf("%d\n", x2);//0
    return 0;
}

6.15 

    printf("输入一个字符串。输出删除空格后的字符串--------------\n");

    /* 初始化两个字符数组,用于存储原始字符串和处理后的字符串 */
    char str[128] = "";//原始字符串
    char str_new[128] = "";//处理后的字符串
    
    /* 初始化计数器,用于跟踪新字符串中的字符位置 */
    int count = 0;

    printf("请输入字符串:");
    
    /* 获取用户输入的字符串,gets函数已弃用最好替换为更安全的函数如fgets */
    gets(str);//因为有空格所以无法使用scanf
    
    /* 遍历用户输入的字符串,去除空格 */
    for (int i = 0; i < strlen(str); i++)
    {
        /* 如果当前字符是空格,则跳过,不将其添加到新字符串中 */
        if (str[i] == ' ')
        {
            continue;//跳过空格赋值,原来的字符串继续再++,而需要的字符串计数器跳过++
        }
        str_new[count] = str[i];
        count++;
    }
    
    /* 输出处理后的字符串 */
    printf("删除空格后的字符串为:%s\n", str_new);



int main(int argc, const char *argv[])
{
    printf("输入一个字符串,实现单词的逆置----------------------\n");
    char str[128] = "";
    char str_new[128] = ""; // 存入删除空格后的字符
    int record[100] = {0};  // 记录每个单词的字符个数
    int count = 0;          // 单词字母个数计数
    int num_word = 0;       // 单词个数
    int num_char = 0;       // 每个的字符个数
    int i = 0;
    int sum_char = 0;                   // 输入的总字符个数
    printf("输入要逆置单词的字符串:"); // 最后以空格结尾
    gets(str);

    for (i = 0; i < strlen(str); i++)
    {
        if (str[i] != ' ')
        {
            num_char++;
        }
        else
        {
            record[count] = num_char;
            num_char = 0;
            count++;
            num_word++;
        }
    }

    printf("单词个数为:%d\n", num_word);
    int count2 = 0;
    for (int i = 0; i < strlen(str); i++) // 删除所有空格
    {
        if (str[i] == ' ')
        {
            continue;
        }
        str_new[count2] = str[i];
        count2++;
    }
    printf("删除空格后的字符串为:%s\n", str_new);
    for (int i3 = 0; i3 < num_word; i3++)
    {
        sum_char += record[i3];
        printf("第%d个单词的字符个数为:%d\n", i3 + 1, record[i3]);
    }
    printf("总字符个数为:%d\n", sum_char);
    printf("下一步逆置字符串----------------------------------\n");
    char temp = 0;
    int x = 0, j = strlen(str_new);
    for (int i1 = 0; i1 < j / 2; i1++)
    {
        temp = str_new[i1];
        str_new[i1] = str_new[j - 1 - i1];
        str_new[j - 1 - i1] = temp;
    }
    printf("逆置后的字符串为:%s\n", str_new);

    printf("下一步逆置单词----------------------------------\n");
    int rec_num_i = 0;
    int rec_num_j = -1;
    for (int count2 = 0; count2 < num_word; count2++) // 几个单词逆置几次
    {
        rec_num_j += record[num_word - count2 - 1];                   // 指向每个单词的尾部
        for (int i2 = rec_num_i, j2 = rec_num_j; i2 < j2; i2++, j2--) // 单词的个数为record[num_word-i2-1]
        {
            temp = str_new[i2];
            str_new[i2] = str_new[j2];
            str_new[j2] = temp;
        }
        rec_num_i += record[num_word - count2 - 1]; // 指向每个单词的头部
    }
    printf("逆置后的字符串为:%s\n", str_new);
    printf("将逆置的字符串内单词加上空格-------------------------\n");
    count2 = 0;
    char str_latest[128] = ""; // 存放加上空格的字符串
    int num_rec = 0;           // 判断什么时候需要加空格的条件变量
    int j3 = 0;
    num_rec += record[num_word - count2 - 1];
    for (int i3 = 0; i3 < sum_char + num_word; i3++)//sum_char + num_word总字符数+空格数
    {
        if (j3 == num_rec)//判断是否需要加空格
        {
            str_latest[j3++] = ' ';//相同则加空格
            count2++;
            num_rec += record[num_word - count2 - 1];
            num_rec++;
        }
        str_latest[j3] = str_new[i3];
        j3++;
    }
    printf("最后字符串为%s\n", str_latest);
    return 0;
}

思路:
        输入字符串后,记录输入的单词数,总字符数,以及每个单词的个数;先删除空格,再逆置,根据每个单词字母个数添加空。

输出:


穷举算法:“鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?”

int main(int argc, const char *argv[])
{
    int x, y, z; // 分别表示鸡翁、鸡母、鸡雏的数量
    for (x = 0; x <= 100; x++)
    { // 鸡翁数量从0到100枚举
        for (y = 0; y <= 100; y++)
        {                    // 鸡母数量从0到100枚举
            z = 100 - x - y; // 根据鸡总数计算鸡雏数量
            if (5 * x + 3 * y + z / 3 == 100)
            { // 检查是否满足价值总和条件
                printf("鸡翁: %d, 鸡母: %d, 鸡雏: %d\n", x, y, z);
            }
        }
    }
    return 0;
}

 输出:


打印99乘法口诀表

    // 使用嵌套循环打印9x9乘法口诀表
    for (int i = 1; i <= 9; i++) { // 外层循环控制行
        for (int j = 1; j <= i; j++) { // 内层循环控制列,只打印到当前行数
            // 打印乘法表达式并适当对齐
            printf("%d*%d=%-2d ", j, i, i*j);
//%-2d是用来保证数字之间的对齐,-2表示至少保留两位宽度,且左对齐。
        }
        // 每打印完一行后换行
        printf("\n");
    }

 输出:


循环输入n个元素,交换数组中最大值和最小值

#include <stdio.h>

int main()
{
    int n;
    printf("请输入数组元素的个数n: ");
    scanf("%d", &n);

    int arr[n];
    printf("请输入%d个整数:\n", n);
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &arr[i]);
    }

    // 初始化最大值和最小值及其索引
    int maxVal = arr[0], minVal = arr[0], maxIdx = 0, minIdx = 0;

    // 遍历数组找到最大值和最小值及其索引
    for (int i = 1; i < n; i++)
    {
        if (arr[i] > maxVal)
        {
            maxVal = arr[i];
            maxIdx = i;
        }
        else if (arr[i] < minVal)
        { // 注意这里是else if,避免重复检查已经判断为最大值的元素
            minVal = arr[i];
            minIdx = i;
        }
    }

    // 直接在数组中交换最大值和最小值,而不是使用单独的swap函数
    arr[maxIdx] = minVal;
    arr[minIdx] = maxVal;

    printf("交换最大值和最小值后,数组为:\n");
    for (int i = 0; i < n; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

 输出: 


 输入字符串,输入变量k的值,将字符循环右移k位

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

int main()
{
    char str[100];
    int k, len;

    printf("请输入字符串: ");
    fgets(str, sizeof(str), stdin); // 使用fgets读取,包括空格,相当于gets(str)

    printf("请输入整数k(循环右移的位数): ");
    scanf("%d", &k);

    // 计算字符串长度并处理k值,确保k在字符串长度范围内
    len = strlen(str);
    k %= len;
    if (k > 0)
    { // 如果k为0,则不需要移动
        // 创建一个临时存储空间来帮助移动字符
        char temp[len];

        // 将字符串后k个字符复制到临时数组前部
        for (int i = 0; i < k; i++)
        {
            temp[i] = str[len - k + i];
        }

        // 将字符串前len-k个字符复制到临时数组剩余部分
        for (int i = k; i < len; i++)
        {
            temp[i] = str[i - k];
        }

        // 将临时数组内容复制回原字符串
        for (int i = 0; i < len; i++)
        {
            str[i] = temp[i];
        }
    }

    printf("循环右移后字符串为: %s\n", str);

    return 0;
}

输出:

6.20

 用shell指令将网址www.hqyj.com截取出网址的每一个部分(要求,该网址不能存入文件中)

 echo "www.hqyj.com" | cut -d "." -f 2 

输出

shell指令

 6.24

  • 写一个shell脚本,将以下内容放到脚本中:
  1. 在家目录下创建目录文件,dir
  2. dir下创建dir1和dir2
  3. 把当前目录下的所有文件拷贝到dir1中,
  4. 把当前目录下的所有脚本文件拷贝到dir2中
  5. 把dir2打包并压缩为dir2.tar.xz
  6. 再把dir2.tar.xz移动到dir1中
  7. 解压dir1中的压缩包
  8. 使用tree工具,查看dir下的文件
    #!/bin/bash
    mkdir -p ~/dir
    mkdir -p ~/dir/dir1/dir2
    cp ./* ~/dir/dir1 -r
    cp ./*.sh ~/dir/dir1/dir2 
    tar -cvf ~/dir2.tar ~/dir2
    tar -cvJf ~/dir2.tar.xz ~/dir2
    mv ~/dir2.tar.xz ~/dir/dir1
    tar -xvJf ~/dir1.tar.xz 
    tree ~/dir
    

  • 写一个脚本,包含以下内容:
  1. 显示/etc/group文件中第五行的内容
  2. 创建目录/home/ubuntu/copy
  3. 切换工作路径到此目录
  4. 赋值/etc/shadow到此目录,并重命名为test
  5. 将当前目录中test的所属用户改为root
  6. 将test中其他用户的权限改为没有任何权限
#!/bin/bash
head -5 /etc/group | tail -1  
mkdir /home/ubuntu/copy
cd /home/ubuntu/copy
cp /etc/shadow /home/ubuntu/copy
mv /home/ubuntu/copy/shadow /home/ubuntu/copy/test
sudo chown root /home/ubuntu/copy/test
chomd o-w,o-r,o-x /home/ubuntu/copy/test

6.25

已知网址www.hqyj.com,使用expr截取出www、hqyj、com,不能使用cut,不能出现数字

#!/bin/bash
str='www.hqyj.com'
len=`expr length "$str"` #获取字符串长度
echo len=$len
num1=`expr index "$str" "."` #获取第一个.的位置
str1=`expr substr "$str" 1 $((num1-1))` #获取第一个.前面的字符串
echo str1=$str1
str2=`expr substr "$str" $((num1+1)) $(($len-$num1))` #获取第一个.后面的字符串
echo str2=$str2
num2=`expr index "$str2" "."`
str3=`expr substr "$str2" 1 $((num2-1))` #获取第二个.前面与第一个.后面的字符串
echo str3=$str3
str4=`expr substr "$str2" $((num2+1)) $(($len-$num1-num2))` #获取第二个.后面的字符串
echo str4=$str4

输出:

6.27

Ubuntu中统计家目录下.c文件的个数

ls -l ~/*.c | wc -l


终端输入一个.sh文件,判断文件是否由可执行权限,如果有可执行权限运行脚本,没有可执行权限添加可执行权限后,再运行脚本

#!/bin/bash
read -p "请输入一个.sh文件:" file
if [ -x "$file" ]
then
        bash $file
else
        echo $file "没有可执行权限,故添加可执行权限"
        chmod 0777 "$file" #chmod u+x 
        bash $file
fi


输出当前用户uid和gid,并使用变量接收结果

#!/bin/bash
num_u=`id -u`
num_g=`id -g`
echo uid=$num_u
echo gid=$num_g

终端输入年月,判断该月有多少天,考虑闰平年的情况

#!/bin/bash
read -p "请输入年份:" year
read -p "请输入月份:" month
flag=0
if [ $((year%400)) -eq 0 ] || [ $((year%4)) -eq 0 ] && [ $((year%100)) -ne 0 ]
then
        echo "闰年"
        flag=1
else
        echo "非闰年"
        flag=0
fi
case  $month in 
        12|10|8|7|1|3|5)
                echo "该月有31天"
                ;;
        11|9|6|4)
                echo "该月有30天"
                ;;
        2)
                echo "该月有$((29-$flag))"
                ;;
        *)
                echo "傻X输入错误"
                ;;
esac   

使用for循环,输出九九乘法表( printf "%d * %d = %d" $i $j $((i*j)) )

#!/bin/bash
for ((i=1;i<10;i++)) 
do
        for((j=1;j<=i;j++))
        do
                printf "%d * %d = %d  " $j $i $((i*j))
        done
        echo
done

使用for循环,找到家目录下的所有.c文件,如果文件有内容编译该文件,如果文件中没有内容,删除文件

#!/bin/bash
for i in `ls /home/ubuntu/*.c`
do
        if [ -s "$i" ]
        then
                gcc $i
                ./a.out
        else
                rm $i
        fi
done

 数据结构简单例题

7.1

在堆区空间连续申请5个int类型大小空间,用来存放从终端输入的5个学生成绩,然后显示5个学生成绩,再将学生成绩升序排序,排序后,再次显示学生成绩。显示和排序分别用函数完成

#include <myhead.h>
void my_display(int * p1)
{
        for(int i=0;i<5;i++)
        {
                printf("第%d成绩为%d\n",i+1,p1[i]);
        }
}
void my_sort(int * p1)
{
        int temp=0;
        for(int i=0;i<5;i++)
        {
                for(int j=i+1;j<5;j++)
                {
                        if(p1[i]>p1[j])
                        {
                                temp=p1[i];
                                p1[i]=p1[j];
                                p1[j]=temp;
                        }
                }
        }
}
int main(int argc, const char *argv[])
{
        int * p1 = (int *)malloc(sizeof(int)*5);
        for(int i=0;i<5;i++)
        {
                printf("请输入第%d个学生成绩:",i+1);
                scanf("%d",&p1[i]);
        }
        my_sort(p1);
        printf("重新排序后的序列为:\n");
        my_display(p1);
        free(p1);
        p1 =NULL;
        return 0;
}

输出:

在堆区申请两个长度为32的空间,实现两个字符串的比较【非库函数实现】

要求:

1.定义函数,在堆区申请空间;两个申请,主函数需要调用2次

2.定义函数,实现字符串的输入;void input(char *p)

3. 调用函数实现字符串比较,在主函数中输出大小;int my_strcmp(const char *s1,const char *s2)

4. 定义函数,释放空间

#include <myhead.h>

/**
 * 释放内存空间
 * @param p 指向要释放的内存空间的指针
 */
void my_free(char * p)//释放空间
{
    free(p);
    p=NULL;
}

/**
 * 从标准输入读取字符串
 * @param str 用于存储输入字符串的缓冲区
 */
void str_input(char* str)//字符串输入
{
    printf("请输入字符串:\n");
    fgets(str,sizeof(str),stdin);
}

/**
 * 申请内存空间
 * @param size 需要申请的内存大小
 * @return 返回指向申请的内存空间的指针
 */
char*  my_malloc(int size)//申请空间大小
{
    char * p = (char *)malloc(size);
    if (p == NULL) {
        // 检查是否分配成功
        perror("malloc");
        return 1; // 返回错误代码
    }
    return p;
}

/**
 * 比较两个字符串的大小
 * @param str1 第一个字符串
 * @param str2 第二个字符串
 * @return 返回值0表示两个字符串相等,1表示str1大于str2,2表示str1小于str2
 */
int  my_strcmp(char *str1,char *str2)//字符串大小比较
{
    char *p1=str1;
    char *p2=str2;
    
    while(*p1 == *p2)
    {
        if(*p1=='\0' || *p2=='\0')
        {
            break;
        }
        p1++;
        p2++;
    }
    int dif_value=*p1-*p2;
    if (dif_value > 0)
    {
        return 1;
    }
    else if(dif_value == 0)
    {
        return 0;
    }
    else
    {
        return 2;
    }

}

int main(int argc, const char *argv[])
{
    char * p1=my_malloc(32);
    str_input(p1);

    char * p2=my_malloc(32);
    str_input(p2);

    int size=my_strcmp(p1,p2);
    
    switch (size)
    {
        case 0: printf("str1=str2\n");
                break;
        case 1: printf("str>str2\n");
                break;
        case 2: printf("str<str2\n");
                break;
        default: printf("输出有误!");
                break;
    }

    //释放空间
    my_free(p1);
    my_free(p2);
    return 0;
}

输出:

7.2 

多文件实现编译

#includ <myhead.h>集成包含的所有需要的头文件

main.c

#include <myhead.h>
#include "fun.h" 
int main(int argc, const char *argv[])
{
    char *p1 = my_malloc(32);
    str_input(p1);

    char *p2 = my_malloc(32);
    str_input(p2);

    int size = my_strcmp(p1, p2);

    switch (size)
    {
    case 0:
        printf("str1=str2\n");
        break;
    case 1:
        printf("str>str2\n");
        break;
    case 2:
        printf("str<str2\n");
        break;
    default:
        printf("输出有误!");
        break;
    }

    // 释放空间
    my_free(p1);
    my_free(p2);
    return 0;
}

fun.c

#include "fun.h"
/**
 * 释放内存空间
 * @param p 指向要释放的内存空间的指针
 */
void my_free(char *p) // 释放空间
{
    free(p);
    p = NULL;
}

/**
 * 从标准输入读取字符串
 * @param str 用于存储输入字符串的缓冲区
 */
void str_input(char *str) // 字符串输入
{
    printf("请输入字符串:\n");
    fgets(str, sizeof(str), stdin);
}

/**
 * 申请内存空间
 * @param size 需要申请的内存大小
 * @return 返回指向申请的内存空间的指针
 */
char *my_malloc(int size) // 申请空间大小
{
    char *p = (char *)malloc(size);
    return p;
}

/**
 * 比较两个字符串的大小
 * @param str1 第一个字符串
 * @param str2 第二个字符串
 * @return 返回值0表示两个字符串相等,1表示str1大于str2,2表示str1小于str2
 */
int my_strcmp(char *str1, char *str2) // 字符串大小比较
{
    char *p1 = str1;
    char *p2 = str2;

    while (*p1 == *p2)
    {
        if (*p1 == '\0' || *p2 == '\0')
        {
            break;
        }
        p1++;
        p2++;
    }
    int dif_value = *p1 - *p2;
    if (dif_value > 0)
    {
        return 1;
    }
    else if (dif_value == 0)
    {
        return 0;
    }
    else
    {
        return 2;
    }
}

fun.h

#ifndef __FUN_H__
#define __FUN_H__

#include <myhead.h>
void str_input(char *str) ;
void my_free(char *p);
char *my_malloc(int size);
int my_strcmp(char *str1, char *str2) ;

#endif 

输出:

  

学生管理系统

题目:

代码:

#include <myhead.h>

int menu(int *p);
struct student // 学生信息数据结构体
{
	char name[20];
	float score;
	int age;
};
/*************************打印学生信息***************/
int print_student(struct student s[], int *p)
{
	if (*p == 0)
	{
		printf("\n当前没有学生信息,请先添加学生信息\n");
		return 1;
	}
	printf("\n=================打印学生信息列表====================\n");
	for (int i = 0; i < *p; i++) // 循环输出学生信息
	{
		printf("|第%d个学生信息:姓名:%-5s;年龄:%-3d;分数:%-3.2f\n", i + 1, s[i].name, s[i].age, s[i].score);
	}
	printf("====================学生共计%d个====================\n", *p);
}
/************************返回函数**********************************/
int my_return(int *ret)
{
	if (*ret == 0)
	{
		printf("\n终止当前操作;返回上一步操作\n");
		return 1;
	}
	return 0;
}
/***********************枚举定义*************************************/
enum option
{
	EXIT = 0,
	ADD,	//=1
	DELETE, //=2
	MODIFY, //=3
	FIND,	//=4
	SHOW
};
/************************界面菜单**********************************************/
int menu(int *p)
{
	static int select;
start:
	printf("\n\t------------------------------------------\n");
	printf("\t--------------学生信息管理系统-------------\n");
	printf("\t--------------1、增添学生信息--------------\n");
	printf("\t--------------2、删除学生信息--------------\n");
	printf("\t--------------3、修改学生信息--------------\n");
	printf("\t--------------4、查找学生信息--------------\n");
	printf("\t--------------5、显示学生信息--------------\n");
	printf("\t--------------0、  退出系统  --------------\n");
	printf("\t-------------------------------------------\n\n");
	printf("请输入你选择:\n");

	if (scanf("%d", &select) != 1)
	{
		while (getchar() != '\n')
			; // 清理输入缓冲区直到遇到换行符
		printf("\n输入有误,请重新输入:\n");
		goto start;
	}

	// 检查是否有未读取的字符(例如,用户输入了"1 "后的其他字符)
	int c = getchar();
	if (c != '\n')
	{
		while (getchar() != '\n')
			; // 如果有其他字符,继续清理缓冲区
		printf("\n输入有误,请仅输入单个数字选项:\n");
		goto start;
	}

	if (select >= 0 && select <= 5)
	{ // 判断输入是否正确
		if (*p == 0 && select != 1 && select != 0)
		{
			printf("\n还未添加学生信息,请添加学生信息!\n");
			goto start;
		}
		return select; // 正确则返回输入的值
	}
	else
	{
		printf("\n输入有误,请重新输入:\n");
		goto start;
	}
}
/*****************************增添学生信息**********************************/
int add_stu(struct student s[], int *p)
{
	static int num; // 添加学生个数
	int *ret = &num;
start:
	printf("\n请输入你要添加学生信息的个数:(输入‘0’返回上一步操作)\n");
	if (scanf("%d", &num) != 1)
	{
		while (getchar() != '\n')
			;
		printf("\n输入有误,请重新输入:\n");
		goto start;
	}

	int c = getchar();
	if (c != '\n')
	{
		while (getchar() != '\n')
			; // 如果有其他字符,继续清理缓冲区
		printf("\n输入有误,请仅输入单个数字选项:\n");
		goto start;
	}

	if (num < 1 || num > 50)
	{
		if (num == 0)
		{
			if (my_return(ret)) // 判断是否返回上一步
			{
				return 1;
			}
		}

		printf("\n输入的学生个数应为1到50之间的整数,请重新输入:\n");
		goto start;
	}
	int j = 1;
	for (int i = *p; i < num + *p; i++) // 循环输入学生信息
	{
		struct student temp; // 使用临时结构体存储新学生信息,确保信息完全正确后再复制到数组中

		printf("\n请按顺序输入%d个学生信息:姓名,年龄,分数:\n", j++);
		scanf("%5s %3d %3f", temp.name, &temp.age, &temp.score);							  // 存入临时结构体中
		if (strcmp(temp.name, " ") == 0 || temp.age < 10 || temp.age > 100 || temp.score < 0) // 判断输入是否有效
		{
			printf("\n输入无效,请重新输入。\n");
			i--;
			j--;

			int c;
			while ((c = getchar()) != '\n' && c != EOF);//清空缓存区
	
			memset(&temp, 0, sizeof(temp));//清空临时结构体
			continue;
		}
		// 确认无误后存入结构体
		strcpy(s[i].name, temp.name);
		s[i].age = temp.age;
		s[i].score = temp.score;
	}

	printf("\n=================打印学生信息列表====================\n");
	for (int i = 0; i < num + *p; i++) // 循环输出学生信息
	{
		printf("|姓名:%-5s; 年龄:%-3d; 分数:%-3.2f \n", s[i].name, s[i].age, s[i].score);
	}
	*p += num; // 添加后的总人数重新赋值
	printf("====================学生共计%d个====================\n", *p);
}
/**************************删除学生信息***********************************/
int delete_stu(struct student s[], int *p)
{
	static int sub_num; // 学生下标
	int *ret = &sub_num;
start:
	printf("\n请输入你要删除第几个学生:(输入‘0’返回上一步操作)\n");
	if (scanf("%d", &sub_num) != 1)
	{
		while (getchar() != '\n')
			; // 清理输入缓冲区直到遇到换行符
		printf("\n输入有误,请重新输入:\n");
		goto start;
	}

	int c = getchar();
	if (c != '\n')
	{
		while (getchar() != '\n')
			; // 如果有其他字符,继续清理缓冲区
		printf("\n输入有误,请仅输入单个数字选项:\n");
		goto start;
	}

	if (my_return(ret)) // 判断是否返回上一步
	{
		return 1;
	}

	if (sub_num <= *p && sub_num > 0)
	{
		for (int i = sub_num - 1; i < *p; i++) // 循环覆盖学生信息
		{
			s[i] = s[i + 1];
		}
		printf("\n删除成功。\n");
	}
	else
	{
		printf("\n输入有误,请重新输入:\n");
		goto start;
	}
	*p -= 1;
	printf("\n=================打印学生信息列表====================\n");
	for (int i = 0; i < *p; i++) // 循环输出学生信息
	{
		printf("|姓名:%-5s; 年龄:%-3d; 分数:%-3.2f \n", s[i].name, s[i].age, s[i].score);
	}
	printf("====================学生共计%d个====================\n", *p);
}
/**************************修改学生信息***********************************/
int modify_stu(struct student s[], int *p)
{
	static int sub_num; // 学生下标
	int *ret = &sub_num;
start:
	printf("\n请输入你要修改第几个学生:(输入‘0’返回上一步操作)\n");
	scanf("%d", &sub_num);
	if (sub_num > *p || *p == 0 || sub_num == 0) // 判断输入是否正确
	{
		if (my_return(ret)) // 判断是否返回上一步
		{
			return 1;
		}

		printf("\n输入有误,请重新输入:\n");
		while (getchar() != '\n')
			; // 吸收垃圾字符,防止死循环
		goto start;
	}

	int c = getchar();
	if (c != '\n')
	{
		while (getchar() != '\n')
			; // 如果有其他字符,继续清理缓冲区
		printf("\n输入有误,请仅输入单个数字选项:\n");
		goto start;
	}

	printf("\n请输入修改后的姓名,年龄,分数。\n");
	scanf("%s %d %f", s[sub_num - 1].name, &s[sub_num - 1].age, &s[sub_num - 1].score);

	printf("\n=================打印学生信息列表====================\n");
	for (int i = 0; i < *p; i++) // 循环输出学生信息
	{
		printf("|姓名:%-5s; 年龄:%-3d; 分数:%-3.2f \n", s[i].name, s[i].age, s[i].score);
	}
	printf("====================学生共计%d个====================\n", *p);
}
/**************************查找学生信息***********************************/
int search_stu(struct student s[], int *p)
{
	static int sub_num; // 学生序号
	int *ret = &sub_num;
start:
	printf("\n请输入你要查找的学生序号:(输入‘0’返回上一步操作)\n");
	scanf("%d", &sub_num);
	if (sub_num > *p || sub_num <= 0 || sub_num == 0) // 判断输入是否正确
	{
		if (my_return(ret)) // 判断是否返回上一步
		{
			return 1;
		}
		printf("\n输入有误,请重新输入:\n");
		while (getchar() != '\n')
			; // 吸收垃圾字符,防止死循环
		goto start;
	}
	int c = getchar();
	if (c != '\n')
	{
		while (getchar() != '\n')
			; // 如果有其他字符,继续清理缓冲区
		printf("\n输入有误,请仅输入单个数字选项:\n");
		goto start;
	}
	printf("\n该学生信息为:\n");
	printf("______________________________________\n");
	printf("|姓名:%-5s; 年龄:%-3d; 分数:%-3.2f|\n", s[sub_num - 1].name, s[sub_num - 1].age, s[sub_num - 1].score);
	printf("——————————————————————————————————————\n");
}
/**************************申请空间************************************/
struct student *my_malloc()
{
	struct student *p = (struct student *)malloc(sizeof(struct student) * 50);
	if (p != NULL) // 判断是否申请成功
	{
		return p;
	}
	else
	{
		perror("malloc:");
		return NULL;
	}
}
/**********************主函数****************************/
int main(int argc, const char *argv[])
{
	struct student *ptr = my_malloc();
	int sum = 0;
	int *p = &sum;

	while (1)
	{
		int select = menu(p);

		switch (select)
		{
		case EXIT:
			printf("\n已退出系统\n");
			return 0;

		case ADD:
			// add_stu(ptr, p);
			if (add_stu(ptr, p))
			{
				continue;
			}
			break;

		case DELETE:

			if (delete_stu(ptr, p))
			{
				continue;
			}
			break;

		case MODIFY:

			if (modify_stu(ptr, p))
			{
				continue;
			}
			break;

		case FIND:

			if (search_stu(ptr, p))
			{
				continue;
			}
			break;

		case SHOW:
			print_student(ptr, p);
			break;
		}
	}
	free(ptr);
	ptr = NULL;
	return 0;
}

 输出:

(太多放不下,复制代码自己试试)。

  • 遇到问题

在遇到吸收垃圾字符时,只能吸收一个的问题,第二个字符会被下一下scanf吸收,如果输入字符,则会出现死循环

在上述代码  menu函数  中举例:

原代码:


    scanf("%d", &select);
	if (select >= 0 && select <= 4) // 判断输入是否正确
	{
		return select; // 正确则返回输入的值
	}
	else
	{
		printf("输入有误,请重新输入:\n");
		getchar(); // 吸收垃圾字符,防止死循环
		goto start;
	}

输出:

改进后代码:
解决了不能吸收多个垃圾字符的情况:

	if (scanf("%d", &select) != 1)
	{
		while (getchar() != '\n')
			; // 清理输入缓冲区直到遇到换行符
		printf("输入有误,请重新输入:\n");
		goto start;
	}

	if (select >= 0 && select <= 4)
	{				   // 判断输入是否正确
		return select; // 正确则返回输入的值
	}
	else
	{
		printf("输入有误,请重新输入:\n");
		// 无需单独调用 getchar(),上面的清理逻辑已足够
		goto start;
	}

输出:

添加枚举到switch中增加代码可读性:

enum option{
	EXIT=0,
	ADD,
	DELETE,
	MODIFY,
	FIND
} ;
…………………………
		switch (select)
		{
		case EXIT:
			printf("已退出系统\n");
			return 0;

		case ADD:
			add_stu(ptr, p);
			break;

		case DELETE:
			delete_stu(ptr, p);
			break;

		case MODIFY:
			modify_stu(ptr, p);
			break;

		case FIND:
			search_stu(ptr, p);
			break;
		}

适当使用占位符使输出更加美观:

printf("|姓名:%-5s; 年龄:%-3d; 分数:%-3.2f \n", s[i].name, s[i].age, s[i].score);

在未添加学生信息时仍可以进入其它选项,不符合常识:

设置判断学生数为0 的时候不能进去其它选项

	if (select >= 0 && select <= 4)
	{				   // 判断输入是否正确
		if(*p == 0 && select != 1 && select != 0)
		{
			printf("\n还未添加学生信息,请添加学生信息!\n");
			goto start;
		}
		return select; // 正确则返回输入的值
	}

在输入选项时。输入“ 1 11”,下一个scanf会读取“11”,导致达不到想要的效果:

如:

	if (scanf("%d", &select) != 1)
	{
		while (getchar() != '\n')
			; // 清理输入缓冲区直到遇到换行符
		printf("\n输入有误,请重新输入:\n");
		goto start;
	}

	if (select >= 0 && select <= 4)
	{				   // 判断输入是否正确
		return select; // 正确则返回输入的值
	}
	else
	{
		printf("\n输入有误,请重新输入:\n");
		// 无需单独调用 getchar(),上面的清理逻辑已足够
		goto start;
	}

错误输出:

修改后代码:

	
	if (scanf("%d", &select) != 1) 
	{
		while (getchar() != '\n'); // 清理输入缓冲区直到遇到换行符
		printf("\n输入有误,请重新输入:\n");
		goto start;
	}

	// 检查是否有未读取的字符(例如,用户输入了"1 "后的其他字符)
	int c = getchar();
	if (c != '\n')
	{
		while (getchar() != '\n'); // 如果有其他字符,继续清理缓冲区
		printf("\n输入有误,请仅输入单个数字选项:\n");
		goto start;
	}

输出:

输入学生信息错误直接赋值:

printf("\n请按顺序输入:姓名,年龄,分数。\n");
		for (int i = *p; i < num + *p; i++) // 循环输入学生信息
		{
			scanf("%5s %3d %3f", s[i].name, &s[i].age, &s[i].score);
		}

修改后代码:

新建一个结构体,输入正确后再赋值到原结构体

	for (int i = *p; i < num + *p; i++) // 循环输入学生信息
	{
		struct student temp; // 使用临时结构体存储新学生信息,确保信息完全正确后再复制到数组中
		// int flag = 0;//标记输入是否有效

		printf("\n请按顺序输入:姓名,年龄,分数。\n");
		scanf("%5s %3d %3f", temp.name, &temp.age, &temp.score);							 // 存入临时结构体中
		if (strcmp(temp.name, "") == 0 || temp.age < 10 || temp.age > 100 || temp.score < 0) // 判断输入是否有效
		{
			printf("\n输入无效,请重新输入。\n");
			i--;
			continue;
		}

		// 确认无误后存入结构体
		strcpy(s[i].name, temp.name);
		s[i].age = temp.age;
		s[i].score = temp.score;
	}

重新添加“返回上一步操作”,使界面更加人性化:

首先,我们让my_return函数返回一个布尔值,表示是否需要返回菜单。为了保持与原有逻辑的一致性,我们可以在调用者函数中根据这个返回值决定是否重新调用menu

int my_return(int *ret)
{
	if (*ret == 0)
	{
		printf("\n终止当前操作;返回上一步操作\n");
		return 1;
	}
	return 0;
}

调整add_stu函数以处理my_return的返回值

接下来,在add_stu函数中,根据my_return的返回值决定是否重新调用menu。这里,我们需要在add_stu函数中包含对menu的调用逻辑,以替代原来my_return直接调用menu的行为。

int add_stu(struct student s[], int *p)
{
    .....

    if (my_return(&num, p)) // 如果需要返回到menu
    {
        return 1; // 从add_stu返回,由main函数处理是否重新调用menu
    }
    
    .....
}

main函数处理add_stu的返回

最后,需要在main函数中处理add_stu的返回值,根据返回值决定是否重新调用menu

......

case ADD:
    if(add_stu(ptr, p))
        {     
// 如果add_stu返回1,表示需要重新显示菜单,因此跳过switch-case直接重新开始循环
            continue; 
        }
        break;

......

ps:

此代码没有解决内存溢出问题,在添加学生信息时,可能会造成溢出。(最好利用define定义姓名最大长度);

修改学生信息时,只能全部修改,不能单独修改某一项的信息。

函数运用多个goto 语句导致程序不稳定,老板可能看不惯,慎用。


7.8

C语言实现链表

chain.h

#ifndef __CHAIN_H__
#define __CHAIN_H__

#include <myhead.h>

typedef int Datetyp;

typedef struct node//定义链表结构体
{
	union
	{
		int len;
		Datetyp date;
	};
	struct node *next;

}chainList,*chainPtr;

chainPtr chain_creat();//创建链表

int chain_empyt(chainPtr P);//判空

chainPtr chain_applyfor(Datetyp e);

void chain_show(chainPtr H);//遍历数据

int chain_head_add(chainPtr H,Datetyp e);

int chain_tail_add(chainPtr H,Datetyp e);//尾插

int chain_random_add(chainPtr H,int num,Datetyp e);//随插

int chain_head_del(chainPtr H);//头删

int chain_tail_del(chainPtr H);//尾删

int chain_random_del(chainPtr H,int num);//随删

int chain_modify_loc(chainPtr H,int loc,Datetyp e);//按位置修改

int chain_modify_value(chainPtr H,Datetyp e,Datetyp e2);//按值修改

int chain_find_return(chainPtr H,Datetyp e);//查找值返回节点

int chain_value_reverse(chainPtr H);//节点值反转

void chain_free(chainPtr H);//释放链表
#endif

chain.c

#include "chain.h"
/******创建链表*******/
chainPtr chain_creat()
{
	chainPtr P = (chainPtr)malloc(sizeof(chainList));
	if (P == NULL)
	{
		printf("创建失败!\n");
		return NULL;
	}
	printf("链表创建成功!\n");
	memset(P, 0, sizeof(chainList));
	return P;
}
/****判断链表是否为空*****/
int chain_empyt(chainPtr P)
{
	if (P == NULL)
	{
		printf("判空失败!\n");
		return -1;
	}
	return P->len == 0;
}
/*******申请节点 封装数据*********/
chainPtr chain_applyfor(Datetyp e)
{
	// 申请结点
	chainPtr P = (chainPtr)malloc(sizeof(chainList));
	if (NULL == P)
	{
		printf("申请节点失败!\n");
		return NULL;
	}
	P->date = e; // 封装数据
	P->next = NULL;
	return P;
}
/****************头插*******************/
int chain_head_add(chainPtr H, Datetyp e)
{
	if (H == NULL)
	{
		printf("头插失败!\n");
		return 0;
	}
	chainPtr P = chain_applyfor(e);

	P->next = H->next;
	H->next = P;
	H->len++;
	return 1;
}
/*******遍历数据***************/
void chain_show(chainPtr H)
{
	if (H == NULL || chain_empyt(H))
	{
		printf("遍历失败!\n");
		return;
	}
	chainPtr q = H;
	for (int i = 0; i < H->len; i++)
	{
		q = q->next;
		printf("%d ", q->date);
	}
	printf("\n");
}
/*******************尾插****************/
int chain_tail_add(chainPtr H, Datetyp e)
{
	if (H == NULL)
	{
		printf("尾插失败!\n");
		return -1;
	}
	chainPtr P = chain_applyfor(e);
	chainPtr F = H;
	while (F->next != NULL)
	{
		F = F->next;
	}

	F->next = P;
	P->next = NULL;
	H->len++;

	return 1;
}
/*******************随插*************************/
int chain_random_add(chainPtr H, int num, Datetyp e)
{
	if (H == NULL || num <= 0 || num > H->len)
	{
		printf("随插失败!\n");
		return -1;
	}
	chainPtr P = chain_applyfor(e);
	chainPtr F = H;
	for (int i = 0; i < num - 1; i++)
	{
		F = F->next;
	}

	P->next = F->next;
	F->next = P;
	H->len++;
	return 1;
}
/************头删*************************/
int chain_head_del(chainPtr H)
{
	if (H == NULL || chain_empyt(H))
	{
		printf("头删失败!\n");
		return -1;
	}

	chainPtr F = H->next;
	H->next = F->next;
	free(F);
	F = NULL;
	H->len--;
	return 1;
}
/************尾删*****************/
int chain_tail_del(chainPtr H)
{
	if (H == NULL || chain_empyt(H))
	{
		printf("尾删失败!\n");
		return -1;
	}
	chainPtr F = H;
	while (F->next != NULL)
	{
		F = F->next;
	}
	free(F);
	F = NULL;
	H->len--;
	return 1;
}
/********随删*****************/
int chain_random_del(chainPtr H, int num)
{
	if (H == NULL || num <= 0 || num > H->len || chain_empyt(H))
	{
		printf("随删失败!\n");
		return -1;
	}
	chainPtr F1 = H;
	chainPtr F2 = H;

	for (int i = 0; i < num - 1; i++)
	{
		F1 = F1->next;
	}

	F2 = F1->next;
	F1->next = F2->next;

	free(F2);
	F1 == NULL;
	H->len--;
	return 1;
}
/*****************按位置修改****************/
int chain_modify_loc(chainPtr H, int loc, Datetyp e)
{
	if (H == NULL || loc <= 0 || loc > H->len || chain_empyt(H))
	{
		printf("修改失败!\n");
		return -1;
	}
	chainPtr F = H;
	for (int i = 0; i < loc; i++)
	{
		F = F->next;
	}
	F->date = e;
	return 1;
}
/**************按值修改*********************/
int chain_modify_value(chainPtr H, Datetyp e, Datetyp e2)
{
	if (H == NULL)
	{
		printf("修改失败!\n");
		return -1;
	}
	chainPtr F = H;
	for (int i = 0; i < H->len; i++)
	{
		F = F->next;
		if (F->date == e)
		{
			F->date = e2;
		}
	}
	return 1;
}
/************查找值返回节点******************/
int chain_find_return(chainPtr H, Datetyp e)
{
	if (H == NULL || chain_empyt(H))
	{
		printf("查找失败!\n");
		return -1;
	}
	chainPtr F = H;
	int flag = 0;
	for (int i = 0; i < H->len; i++)
	{
		F = F->next;
		if (F->date == e)
		{
			flag = 1;
			return i + 1;
		}
	}
	if (flag == 0)
	{
		printf("未查到该值!\n");
		return -1;
	}
}
/**************节点值反转***************/
int chain_value_reverse(chainPtr H)
{
	if (H == NULL || chain_empyt(H))
	{
		printf("链表为空,无法反转!\n");
		return -1;
	}
	chainPtr F = H->next;
	chainPtr P = NULL;
	chainPtr Q = NULL;
	while (F != NULL)
	{
		Q = F->next;
		F->next = P;
		P = F;
		F = Q;
	}
	H->next = P;
	return 1;
}
/*************释放链表****************/
void chain_free(chainPtr H)
{
	if(H==NULL)
	{
		printf("销毁失败!\n");
		return;
	}
	chainPtr P = H;
	chainPtr Q = P->next;
	while(Q!=NULL)
	{
		P=Q;
		Q=Q->next;
		free(P);
	}
	printf("销毁成功!\n");
}

main.c

//用于检测代码功能是否完成
#include "chain.h"
int main(int argc, const char *argv[])
{
	chainPtr P=chain_creat();//创建链表
	chain_head_add(P,10);
	chain_head_add(P,20);
	chain_head_add(P,30);
	chain_head_add(P,40);
	chain_head_add(P,50);
	chain_head_add(P,60);
	chain_head_add(P,70);
	chain_head_add(P,80);
	
	chain_show(P);
	chain_value_reverse(P);
	chain_show(P);
	chain_free(P);
	return 0;
}

7.9 双向循环链表

简单实现双向循环列表的:删除,插入,销毁等操作;

main.c

#include "Two_waylink.h"
int main(int argc, const char *argv[])
{
	Two_waylinkPtr H=creat_twolink();
	head_add(H,10);
	head_add(H,20);
	head_add(H,30);
	head_add(H,40);
	head_add(H,50);
	head_add(H,60);
 	show(H);
	tail_del(H);
	show(H);
	tail_add(H,100);
	show(H);
	tail_add(H,666);
	show(H);
	free_twolink(H);
	return 0;
}

Two_waylink.c

#include "Two_waylink.h"
/*********创建双向循环链表**************/
Two_waylinkPtr creat_twolink()
{
	Two_waylinkPtr H=(Two_waylinkPtr)malloc(sizeof(Two_waylink));
	if(H==NULL)
	{
		printf("创建失败!\n");
		return NULL;
	}
	// memset(H,0,sizeof(Two_waylink));
	H->next = H;
	H->prior = H;
	H->len = 0;
	printf("创建成功\n");
	return H;
}
/*********申请节点*****************/
Two_waylinkPtr creat_node(Datetyp e)
{
	Two_waylinkPtr P = (Two_waylinkPtr)malloc(sizeof(Two_waylink));
	if(P==NULL)
	{
		printf("申请节点失败!\n");
		return NULL;
	}
	P->next = NULL;
	P->prior = NULL;
	P->data = e;
	return P;
}
/*********判空*******************/
int empty(Two_waylinkPtr P)
{
	if(P==NULL)
	{
		printf("判空失败!\n");
		return -1;
	}
	return P->prior == P;
}
/**************头插********************/
int head_add(Two_waylinkPtr H,Datetyp e)
{
	if(H==NULL)
	{
		printf("头插失败!\n");
		return -1;
	}
	Two_waylinkPtr P=creat_node(e);
	if(H->next==NULL)
	{		
		H->next=P;
		P->prior=H;

	}
	else
	{
		P->next=H->next;
		P->prior=H;
		H->next->prior=P;
		H->next=P;
	
	}
	H->len++;	
	return 1;
}
/*******遍历节点**************/
void show(Two_waylinkPtr H)
{

	if(H==NULL|| empty(H))
	{
		printf("遍历失败\n");
		return;
	}
	Two_waylinkPtr P=H;
	for(int i=0;i<H->len;i++)
	{
		P=P->next;
	
		printf("%d ",P->data);
	}

	printf("\n");
}
/*******************随插入***********************/
int random_add(Two_waylinkPtr H,int loc,Datetyp e)
{
	if(H==NULL||loc>H->len+1 ||loc<1)
	{
		printf("插入失败!\n");
		return -1;
	}
	Two_waylinkPtr P=H;
	Two_waylinkPtr Q=creat_node(e);

	for(int i =0;i<loc;i++)
	{
		P=P->next;
	}
	if(P->next==NULL)
	{
		P->next=Q;
		Q->prior=P;
		
	}
	else
	{
		Q->next=P;
		Q->prior=P->prior;
		P->prior->next=Q;
		P->prior=Q;

	}
	H->len++;
	return 1;
}
/*********************随删除**********************/
int random_del(Two_waylinkPtr H,int loc)
{
	if(H==NULL || loc>H->len||loc<1||empty(H))
	{
		printf("删除失败!\n");
		return 0;
	}
	Two_waylinkPtr F=H;
	for(int i=0;i<loc;i++)
	{
		F=F->next;
	}
	if(F->next==NULL)
	{
		F->prior->next=NULL;
		F->prior=NULL;
		free(F);
		F=NULL;
	}
	else
	{
		F->prior->next=F->next;
		F->next->prior=F->prior;
		free(F);
		F=NULL;
	}
	H->len--;
	return 1;
}
/***************销毁**************/
void free_twolink(Two_waylinkPtr H)
{
	if(H==NULL)
	{
		printf("销毁失败!\n");
		return ;
	}
	for(int i=0;i<H->len;i++)
	{
		random_del(H,1);
	}
	free(H);
	H=NULL;
	printf("销毁成功!\n");
	return;
}
/********尾删****************/
int tail_del(Two_waylinkPtr H)
{
	if(H==NULL||empty(H))
	{
		printf("尾删失败!\n");
		return -1;
	}
	Two_waylinkPtr P=H;
	for(int i=0;i<H->len;i++)
	{
		P=P->next;
	}
	P->prior->next=H;
	H->prior=P->prior;
	P->prior=NULL;
	H->len--;
	free(P);
	P=NULL;
	return 1;
}
/*******尾插***********/
int tail_add(Two_waylinkPtr H,Datetyp e)
{
	if(H==NULL)
	{
		printf("尾插失败!\n");
		return -1;
	}
	Two_waylinkPtr F=creat_node(e);
	Two_waylinkPtr p=H;
	for (int i = 0; i < H->len; i++)
	{
		p=p->next;
	}
	p->next=F;
	F->next=H;
	F->prior=p;
	H->prior=F;
	H->len++;
	return 1;
}

Two_waylink.h

#ifndef  __TWO_WAYLINK_H__
#define  __TWO_WAYLINK_H__
#include <myhead.h>
typedef int Datetyp;
typedef struct node
{
	union
	{
		int len;//链表长度
		Datetyp data;//数据域
	};
	struct node *next;//向后指针
	struct node *prior;//前向指针
}Two_waylink,*Two_waylinkPtr;

/*****创建双向循环链表*********/
Two_waylinkPtr creat_twolink();

/*********申请节点*****************/
Two_waylinkPtr creat_node(Datetyp e);

/*********判空************/
int empty(Two_waylinkPtr P);

/**************头插********************/
int head_add(Two_waylinkPtr H,Datetyp e);

/*******遍历节点***********/
void show(Two_waylinkPtr H);

/*******************随插入***********************/
int random_add(Two_waylinkPtr H,int loc,Datetyp e);

/****************随删除****************/
int random_del(Two_waylinkPtr H,int loc);

/***************销毁**************/
void free_twolink(Two_waylinkPtr H);

/********尾删****************/
int tail_del(Two_waylinkPtr H);

/*******尾插***********/
int tail_add(Two_waylinkPtr H,Datetyp e);

#endif

输出:


7.10链式队列的简单实现

queueLink.c

#include "queueLink.h"
/****申请链表队列*****/
queuePtr create()
{
    queuePtr Q = (queuePtr)malloc(sizeof(queue));
    if (Q == NULL)
    {
        printf("申请失败!\n");
        return NULL;
    }
    Q->head = (NodePtr)malloc(sizeof(Node));
    if (Q->head == NULL)
    {
        printf("申请失败!\n");
        free(Q);
        Q = NULL;
        return NULL;
    }
    Q->head->len = 0;
    Q->head->next = NULL;
    Q->tail = Q->head;
    printf("申请成功!\n");
    return Q;
}
/******申请节点********/
NodePtr create_node(Datetyp e)
{
    NodePtr N = (NodePtr)malloc(sizeof(Node));
    if (N == NULL)
    {
        printf("申请失败!\n");
        return NULL;
    }
    N->next = NULL;
    N->data = e;
    return N;
}
/******判空**********/
int empty(queuePtr Q)
{
    if (Q == NULL)
    {
        printf("判空失败!\n");
        return -1;
    }
    return Q->head == Q->tail;
}
/********入队**********/
int push(queuePtr Q, Datetyp e)
{
    if (Q == NULL)
    {
        printf("入队失败!\n");
        return -1;
    }
    NodePtr N = create_node(e);
    Q->tail->next = N;
    Q->tail = N;

    Q->head->len++;
    return 1;
}
/********遍历*********/
void show(queuePtr Q)
{
    if (Q == NULL || empty(Q))
    {
        printf("遍历失败\n");
    }
    NodePtr N = Q->head;
    while (N->next != NULL)
    {
        N = N->next;
        printf("%d ", N->data);
    }

    putchar(10);
}
/***********出队(尾删)***********/
int pop_tail(queuePtr Q)
{

    if (Q == NULL || empty(Q))
    {
        printf("出队失败!\n");
        return -1;
    }

    NodePtr N = Q->head;

    for (int i = 0; i < Q->head->len - 1; i++)
    {
        N = N->next;
    }
    free(N->next);
    N->next = NULL;
    Q->tail = N;
    Q->head->len--;
    return 1;
}
/***********出队(头删)***********/
int pop_head(queuePtr Q)
{

    if (Q == NULL || empty(Q))
    {
        printf("出队失败!\n");
        return -1;
    }

    NodePtr N = Q->head;
    N = N->next;
    Q->head->next = N->next;
    N->next = NULL;

    free(N);

    Q->head->len--;
    return 1;
}
/*****链表长度**********/
int len(queuePtr Q)
{
    if (Q == NULL || empty(Q))
    {
        printf("求长度失败!\n");
        return -1;
    }
    printf("长度=%d\n", Q->head->len);
    return Q->head->len;
}
/********销毁链表***********/
int free_queue(queuePtr Q)
{
    if (Q == NULL)
    {
        printf("销毁失败!\n");
        return -1;
    }
    for (int i = 0; i < Q->head->len; i++)
    {
        pop_head(Q);
    }
    printf("销毁成功!\n");
    return 1;
}

queueLink.h

#ifndef __QUEUELINK_H__
#define __QUEUELINK_H__
#include <myhead.h>
typedef int Datetyp;

typedef struct node
{
    union
    {
        int len;
        Datetyp data;
    };
    struct node *next;
} Node, *NodePtr;

typedef struct queue
{
    Node *head;
    Node *tail;
} queue, *queuePtr;

/****申请链表队列*****/
queuePtr create();

/******申请节点********/
NodePtr create_node(Datetyp e);

/******判空**********/
int empty(queuePtr Q);

/********入队**********/
int push(queuePtr Q, Datetyp e);

/********遍历*********/
void show(queuePtr Q);

/***********出队(尾删)***********/
int pop_tail(queuePtr Q);

/***********出队(头删)***********/
int pop_head(queuePtr Q);

/********销毁链表***********/
int free_queue(queuePtr Q);
#endif

main.c

#include "queueLink.h"
int main()
{
    queuePtr Q = create();
    push(Q, 10);
    push(Q, 20);
    push(Q, 30);
    push(Q, 40);
    push(Q, 50);
    show(Q);
    pop_head(Q);
    show(Q);
    free_queue(Q);

    return 0;
}

输出:

 文件IO

思维导图

7.15

使用 fputc 和 fgetc 实现文件的拷贝功能;

源代码

#include <myhead.h>
int main(int argc, const char *argv[])
{
    FILE *rfp=fopen(argv[1],"r");
    FILE *wfp=fopen(argv[2],"w");
    if (wfp==NULL||rfp==NULL)
    {
        perror("fopen");
        return 1;
    }
    unsigned char ch=0;//一定要是无符号字符类型,不写unsigned就跳不出循环
    while (1)
    {
        ch = fgetc(rfp);//读文本
        if (ch==255)//结束跳出循环
        {
            break;
        }
        fputc(ch,wfp);//写入文本
    }
    fclose(wfp);
    fclose(rfp);
    
    return 0;
}

使用 fprintf 和 fscanf实现文件的拷贝功能;

#include <myhead.h>
int main(int argc, const char *argv[])
{
    FILE *fpr=fopen(argv[1],"r");
    FILE *fpw=fopen(argv[2],"w");
    if (fpr==NULL || fpw==NULL)
    {
        perror("fopen");
        return 1;
    }
    char ch=0;
 /*  while (feof(fpr)!=1)
    {
        fscanf(fpr,"%c",&ch);
        fprintf(fpw,"%c",ch);
    }
*/
    while (fscanf(fpr,"%c",&ch) != -1)
    {

        fprintf(fpw,"%c",ch);
    }
    fclose(fpw);
    fclose(fpr);
    return 0;
}

使用 fprintf 和 fscanf 实现对结构体数组内数据的提取到文件和从文件再赋值过程;

 源代码:

#include <myhead.h>
typedef struct Student
{
    char name[20];
    int chinese;
    int math;
    int english;
    int physics;
    int chemical;
    int biology;
} su;
int main(int argc, char const *argv[])
{
    su arr[5] =
        {
            {"qqq", 11, 11, 11, 11, 11, 11},
            {"www", 22, 22, 22, 22, 22, 22},
            {"eee", 33, 33, 33, 33, 33, 33},
            {"rrr", 44, 44, 44, 44, 44, 44},
            {"ttt", 55, 55, 55, 55, 55, 55}};
    FILE *wfp = fopen(argv[1], "w");
    if (wfp == NULL)
    {
        perror("wfp");
        return 1;
    }

    for (int i = 0; i < 4; i++)
    {
        fprintf(wfp, "%s %d %d %d %d %d %d\n", arr[i].name, arr[i].biology, arr[i].chemical, 
        arr[i].chinese, arr[i].english, arr[i].math, arr[i].physics);
    }

    memset(arr, 0, sizeof(arr));
    FILE *rfp = fopen(argv[1], "r");
    if (rfp == NULL)
    {
        perror("rfp");
        return 1;
    }
    char ptr;
    int num;
    fclose(wfp);
    
    for (int i = 0; i < 4 ; i++)
    {
        fscanf(rfp, "%s %d %d %d %d %d %d\n", arr[i].name, &arr[i].chinese, &arr[i].biology, 
        &arr[i].chemical, &arr[i].english, &arr[i].math, &arr[i].physics);
    }

    for (int i = 0; i < 4; i++)
    {
        printf("%s %d %d %d %d %d %d\n", arr[i].name, arr[i].biology, arr[i].chemical, 
        arr[i].chinese, arr[i].english, arr[i].math, arr[i].physics);
    }
    fclose(rfp);
    return 0;
}


 使用 fprintf 和 fscanf 实现对链表数据的提取到文件和从文件再赋值过程;

 只需要在原链表上加上函数:

/*********将节点内容写入文档中**********/
int fprintf_chain(chainPtr H,const char *filename)
{
	if (H==NULL)//判断链表是否有效
	{
		printf("数据写入文档失败!\n");
		return -1;
	}
	FILE *wfp=fopen(filename,"w");//将数据写入到文档中
	FILE *rfp=fopen(filename,"r");//将文档的数据写入链表
	if (wfp == NULL||rfp==NULL)
    {
        perror("fopen");
        return -1;
    }

	chainPtr W=H;
	chainPtr r=H;
	while (W->next!=NULL)//写入数据到文档
	{
		W=W->next;
		fprintf(wfp,"%d ",W->date);
	}
	fclose(wfp);//关闭
	for(int i=1;i<=H->len;i++)//清空链表数据
	{
		chain_modify_loc(H,i,0);
	}

	printf("清空后:\n");
	chain_show(H);

	while (r->next!=NULL)//从文档中得到数据
	{
		r=r->next;
		fscanf(rfp,"%d ",&(r->date));
		if (feof(rfp)==1)//判断是否到文档最后
		{
			break;
		}
		
	}
	fclose(rfp);
	printf("重新填入后:\n");
	chain_show(H);
	return 1;
}

主函数代码:

#include "chain.h"
int fprintf_chain(chainPtr H,const char *filename);
int main(int argc, const char *argv[])
{
	chainPtr P=chain_creat();//创建链表
	chain_head_add(P,10);
	chain_head_add(P,20);
	chain_head_add(P,30);
	chain_head_add(P,40);
	chain_head_add(P,50);
	chain_head_add(P,60);
	chain_head_add(P,70);
	chain_head_add(P,80);
	
	chain_show(P);
	fprintf_chain(P,argv[1]);		//将节点内容写入文档中


	chain_free(P);
	return 0;
}

输出:

7.16

使用 fwrite和 fread实现文件的拷贝功能;

#include <myhead.h>
int main(int argc, char const *argv[])
{
    // 打开一个文件以写入模式
    FILE* wfp=fopen(argv[2],"w");
    // 打开一个文件以读取模式
    FILE* rfp=fopen(argv[1],"r");
    // 检查文件是否成功打开,如果失败,则输出错误信息并返回1
    if (wfp==NULL||rfp==NULL)
    {
        perror("fopen");
        return 1;
    }
    // 定义一个字符数组用于临时存储读取的数据,如果读取多个字节就用数组
    char ch;
    while (1)
    {
        // 从输入文件读取一个字符,并检查读取是否成功,如果失败,则返回1
        if(fread(&ch,1,1,rfp)==0)
        {
            return 1;
        }
        // 将读取的字符写入输出文件
        fwrite(&ch,1,1,wfp);
    }
    // 关闭输入文件
    fclose(wfp);
    // 关闭输出文件
    fclose(rfp);
    
    return 0;
}

fflush的利用

在终端的界面上输出:__-__-__-__ 1秒过后,变成 1_-__-__-__ 再1秒过后,变成 12-__-__-__ 依此类推 经过8秒,最终变成 12-34-56-78 \b 是printf里面,光标向左移动的转义符

#include <myhead.h>

/* 主函数:程序入口点,接收命令行参数 */
int main(int argc, char const *argv[])
{
    /* 初始化显示进度条的框架 */
    printf("__-__-__-__");
    fflush(stdout); /* 确保输出立即刷新 */
    sleep(1); /* 延迟1秒,为动态显示进度创造时间间隔 */

    /* 逐个替换框架中的字符,模拟进度更新 */
    printf("\b\b\b\b\b\b\b\b\b\b\b"); /* 回退到起始位置 */
    fflush(stdout);
    printf("1"); /* 显示第一个数字 */
    fflush(stdout);
    sleep(1); /* 延迟1秒 */

    /* 以下类似,逐步显示进度 */
    printf("2-");
    fflush(stdout);
    sleep(1);
    printf("3");
    fflush(stdout);
    sleep(1);
    printf("4-");
    fflush(stdout);
    sleep(1);
    printf("5");
    fflush(stdout);
    sleep(1);
    printf("6-");
    fflush(stdout);
    sleep(1);
    printf("7");
    fflush(stdout);
    sleep(1);
    printf("8");
    fflush(stdout);
    sleep(1);

    /* 输出换行符,结束进度条显示 */
    putchar(10);
    return 0; /* 程序正常结束 */
}

bmp参数的更改 

将一张bmp图片的大小更改成原来的4倍,宽度和高度都要对应的变成原来的2倍,多出来的像素点用黑色填充

bmp图片格式:

#include <myhead.h>
int main(int argc, char const *argv[])
{
    /* 打开命令行参数指定的文件,以读写模式 */
    FILE *fp = fopen(argv[1], "r+");

    int size, hight, weight;

    /* 定位到文件的第3个字节,读取图像大小 */
    fseek(fp, 2, SEEK_SET);
    fread(&size, 4, 1, fp);
    printf("大小=%d字节\n", size); // 读大小

    size = size * 4;
    fseek(fp, 2, SEEK_SET);
    fwrite(&size, 4, 1, fp); // 大小放大四倍

    fseek(fp, 2, SEEK_SET); // 再次读取大小
    fread(&size, 4, 1, fp);
    printf("放大后大小=%d字节\n", size);

    fseek(fp, 18, SEEK_SET); //读取宽度
    fread(&weight, 4, 1, fp);
    weight = weight * 2;//宽度×2
    fseek(fp, 18, SEEK_SET);
    fwrite(&weight, 4, 1, fp);//重新写入

    fseek(fp, 18, SEEK_SET);
    fread(&weight, 4, 1, fp);//重新读取

    fseek(fp, 22, SEEK_SET);//读取长度
    fread(&hight, 4, 1, fp);
    hight = hight * 2;
    fseek(fp, 22, SEEK_SET);
    fwrite(&hight, 4, 1, fp);//填入长度

    fseek(fp, 22, SEEK_SET);
    fread(&hight, 4, 1, fp);//重新读取长度

    /* 输出图像的基本信息 */
    printf("像素=%d * %d\n", weight, hight);

    /* 定位到文件的第55个字节,准备写入RGB数据 */
    fseek(fp, 54, SEEK_SET);
    unsigned char rgb1[3] = {0, 0, 0}; // 黑色
    unsigned char rgb2[3] = {38, 27, 173};
    unsigned char rgb3[3] = {0, 166, 255}; // 金色
    /* 循环遍历每一行,将红色填充到整个图像 */

    for (int i = 0; i > hight; i++)
    {
        for (int j = 0; j > weight; j++)
        {
            if (i > hight / 3)
            {
                fwrite(rgb1, 3, 1, fp);
            }
        }
    }

    /* 关闭文件 */
    fclose(fp);
    return 0;
}

 写不了一点!!

 7.17

dup的使用

使用dup,dup2实现一下功能 按照如下代码顺序输出 printf("hello\n") printf("world\n") 要求,hello输出到文件中,world输出到终端上

#include  <myhead.h>
int main(int argc, char const *argv[])
{
    // 复制标准输出文件描述符,以便后续将输出重定向到其他位置
    dup(STDOUT_FILENO);                                  //sdtin sdtout sdterr sdtout
    
    // 打开命令行参数指定的文件,以读写方式创建(如果不存在)并清空文件内容
    // 文件权限设置为0777,表示所有用户都有读写执行权限
    int fp=open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0777);    //sdtin sdtout sdterr sdtout fp
    
    // 将文件描述符fp复制到标准输出,从此标准输出将写入到指定文件中
    dup2(fp,1); //sdtin fp     sdterr sdtout fp
    
    // 输出字符串"hello"到标准输出,此时标准输出已经重定向到文件中
    printf("hello\n");
    
    // 强制刷新标准输出缓冲区,确保"hello"被立即写入到文件中
    fflush(stdout);
    
    // 将文件描述符3复制到标准输出,用于后续的输出重定向
    // 注意:这里假设文件描述符3已经在其他地方被正确设置和准备
    dup2(3,STDOUT_FILENO);                                //sdtin fp     sdterr sdtout fp
    
    // 输出字符串"Word!"到标准输出,此时标准输出被重定向到新的位置
    printf("Word!\n");
    
    // 程序正常结束
    return 0;
}


 通过 opendir、readdir、write、read函数实现拷贝一个文件夹中的所有文件的功能

#include <myhead.h>
int main(int argc, char const *argv[])
{
    /* 打开目录“./11” */
    DIR *afp = opendir("./11");
    /* 检查目录是否成功打开 */
    if (afp == NULL)
    {
        perror("opendir");
        return 1;
    }
    struct dirent *dir;

    char buf[128];
    /* 遍历目录中的每个文件 */
    while ((dir = readdir(afp)) != NULL)
    {
        /* 忽略当前目录“.”和父目录“..” */
        if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
        {
            continue;
        }
        char file_write[128];
        char open_read[128];
        /* 构建原文件的完整路径 */
        memset(open_read, 0, sizeof(open_read));//清空数组
        strcat(open_read, "./11/");//添加路径
        strcat(open_read, dir->d_name);//路径和文件名拼接
        /* 打开原文件以只读方式 */
        int rfp = open(open_read, O_RDONLY);
        /* 检查文件是否成功打开 */
        if (rfp == -1)
        {
            perror("open");
            return 1;s
        }
        /* 构建新文件的名称 */
        memset(file_write, 0, sizeof(file_write));
        strcat(file_write, open_read);
        strcat(file_write, "copy");
        /* 打开新文件以写入方式,如果不存在则创建 */
        int wfp = open(file_write, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        /* 从原文件读取数据并写入新文件 */
        while (1)
        {
            int size = read(rfp, buf, 128);
            int len = strlen(buf);
            /* 如果读取结束或读取到空字符串,则退出循环 */
            if (size <= 0 || len == 0)
            {
                break;
            }
            write(wfp, buf, size);
        }
        /* 关闭原文件和新文件 */
        close(wfp);
        close(rfp);
    }

    /* 关闭目录 */
    closedir(afp);
    return 0;
}

7.18

Linux终端中实现伪终端 

#include <myhead.h> // 包含自定义头文件或标准库,用于声明后续使用的函数

// 函数功能:从标准输入读取一行文本到缓冲区buf中,并移除末尾的换行符
char *getLine(char *buf, int size)
{
    fgets(buf, size, stdin); // 从标准输入读取一行最多size-1个字符到buf中
    int len = strlen(buf);   // 获取buf中的字符串长度
    if (buf[len - 1] == '\n')
    {                     // 如果字符串以换行符结束
        buf[len - 1] = 0; // 将换行符替换为字符串终止符,移除换行符
    }
}
int main(int argc, const char *argv[])
{
    while (1)
    {                        // 无限循环,模拟伪终端的持续运行
        int retval = fork(); // 创建子进程
        if (retval > 0)    // 父进程
        {        
            wait(0); // 等待任意子进程结束
        }
        else    // 子进程
        {                            
            char *username = getlogin(); // 获取当前登录用户名
            char hostname[64] = {0};     // 初始化一个64字节大小的主机名缓存区
            char pwd[128] = {0};         // 初始化一个128字节大小的当前工作目录缓存区
            gethostname(hostname, 64);   // 获取主机名并存储在hostname中
            getcwd(pwd, 128);            // 获取当前工作目录并存储在pwd中
            // 打印欢迎信息,使用ANSI转义序列设置字体颜色和样式

            /*
                    \033[ 是转义序列的开始,\033 是 ASCII 字符集中的 Escape 字符(ASCII值为27)

                    1;32;10m 是一系列的代码,它们之间用分号 ;

                    1 表示启用高亮(通常是加粗)模式。
                    32 表示设置前景色为绿色。
                    \033[0m 是重置所有样式和颜色到默认状态的转义序列。
            */
            printf("\033[1;32;10m%s@%s\033[0m:\033[1;34;10m%s\033[0m$ ", username, hostname, pwd);

            fflush(stdout); // 刷新标准输出流,确保信息立即显示

            char *arg[20] = {0}; // 初始化一个最多20个元素的命令参数指针数组

            // 以下代码用于读取用户输入的命令并解析成参数数组
            char cmd[128] = {0}; // 初始化一个128字节大小的命令缓存区 

            getLine(cmd, 128);   // 函数功能:从标准输入读取一行文本到缓冲区buf(cmd)中,并移除末尾的换行符(读取用户输入的命令)

            char *token = NULL; // 初始化用于存储分割出的命令参数
            int i = 0;          // 初始化参数索引
            do
            {
                if (token == NULL)
                {
                    token = strtok(cmd, " "); // 使用空格分割命令,获取第一个参数
                }
                else
                {
                    token = strtok(NULL, " "); // 继续分割剩余的参数
                }
                arg[i++] = token; // 将参数添加到arg数组中
            } while (token != NULL); // 直到所有参数被分割完毕

            // 检查并执行命令
            if (strcmp(arg[0], "cd") == 0)
            {                  // 如果命令是"cd"
                chdir(arg[1]); // 改变当前工作目录
            }
            else
            {
                execvp(arg[0], arg); // 执行外部命令,arg[0]是命令名,arg是参数数组
                // 如果execvp返回,表示命令未找到或执行失败
                printf("没有找到该指令\n"); // 输出错误信息
            }
            // 子进程执行完命令后会自动退出,无需return 0;
        }
    }
    return 0; 
}

7.19 

测试错误检查锁和递归锁是否会造成死锁状态

#include <myhead.h>

// 定义两个互斥锁,用于线程间的同步和互斥访问
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;


void *run(void *PTR)
{
    while (1)
    {
        // 加锁mutex2,确保线程安全地访问共享资源
        pthread_mutex_lock(&mutex2);
        printf("999\n");
        sleep(1);
        // 解锁mutex2,释放对共享资源的锁定
        pthread_mutex_unlock(&mutex2);
    }
    return NULL;
}

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

    // 设置互斥锁属性为错误检查类型
    pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK_NP);

/* 设置互斥锁属性为递归类型类型
   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
*/

    // 初始化mutex1,使用错误检查类型的互斥锁
    pthread_mutex_init(&mutex1, &mutex_attr);
    
    // 初始化mutex2,使用相同的错误检查类型的互斥锁
    pthread_mutex_init(&mutex2, &mutex_attr);

    pthread_t id;
    // 创建一个新的线程并运行run函数
    pthread_create(&id, 0, run, NULL);
    // 分离线程,使其在结束时不需要等待
    pthread_detach(id);

    while (1)
    {
        // 加锁mutex1,确保线程安全地访问共享资源
        pthread_mutex_lock(&mutex1);
        printf("666\n");
        sleep(1);
        // 解锁mutex1,释放对共享资源的锁定
        pthread_mutex_unlock(&mutex1);
    }

    return 0;
}

误检查锁和递归锁不会造成死锁现象。

火车过隧道问题

#include <myhead.h>

// 定义快速隧道和慢速隧道的常量
#define FAST_TUNNEL 1
#define SLOW_TUNNEL 2

// 初始化互斥锁,注意:这里没有使用PTHREAD_MUTEX_INITIALIZER,需要在main函数中初始化
pthread_mutex_t block1 ;
pthread_mutex_t block2 ;

// 火车结构体
typedef struct {
    int id;              // 火车ID
    int type;            // 火车型号:1表示复兴号,2表示绿皮车
    int tunnel;          // 当前使用的隧道:0表示未进入隧道
    int speed;           // 火车速度(用于模拟通过隧道所需时间)
    int passed;          // 是否已经通过隧道:0表示未通过,1表示已通过
} Train;

// 火车数组,初始化火车信息
Train trains[] = {
    {1, 1, 0, 300, 0},   // 复兴号,速度300,未通过隧道
    {2, 1, 0, 300, 0},   // 复兴号,速度300,未通过隧道
    {3, 1, 0, 300, 0},   // 复兴号,速度300,未通过隧道
    {4, 2, 0, 100, 0},   // 绿皮车,速度100,未通过隧道
    {5, 2, 0, 100, 0},   // 绿皮车,速度100,未通过隧道
};

// 线程运行函数
void *run(void *arg) {
    // 从参数中获取火车索引
    int index = *(int *)arg;
    // 根据索引获取火车实例
    Train *train = &trains[index];

    // 如果火车已经通过隧道,直接返回,不再执行后续逻辑
    if (train->passed) {
        return NULL;
    }

    // 用于锁定隧道的互斥锁指针
    pthread_mutex_t *tunnel_lock = NULL;
    // 当前使用的隧道编号
    int tunnel = 0;

    // 判断火车类型
    if (train->type == 1) { // 如果是复兴号
        // 尝试锁定快速隧道
        pthread_mutex_lock(&block1);
        tunnel_lock = &block1;
        tunnel = FAST_TUNNEL;
        // 如果快速隧道不可用,解锁快速隧道并尝试锁定慢速隧道
        if (!tunnel_lock) {
            pthread_mutex_unlock(&block1);
            pthread_mutex_lock(&block2);
            tunnel_lock = &block2;
            tunnel = SLOW_TUNNEL;
        }
    } else { // 如果是绿皮车
        // 直接锁定慢速隧道
        pthread_mutex_lock(&block2);
        tunnel_lock = &block2;
        tunnel = SLOW_TUNNEL;
    }

    // 如果成功锁定隧道
    if (tunnel_lock != NULL) {
        // 设置火车当前使用的隧道
        train->tunnel = tunnel;
        // 输出火车开始使用隧道的信息
        printf("火车 %d 正在使用隧道 %d。\n", train->id, tunnel);
        // 模拟火车通过隧道所需的时间(usleep参数单位为微秒)
        usleep(train->speed * 5000);
        // 输出火车结束使用隧道的信息
        printf("火车 %d 已经离开隧道 %d。\n", train->id, tunnel);
        // 解锁隧道
        pthread_mutex_unlock(tunnel_lock);
        // 标记火车已经通过隧道
        train->passed = 1;
    }

    // 结束线程
    pthread_exit(NULL);
}

// 主函数
int main(int argc, char const *argv[]) {
    // 循环创建线程
    int i;
    pthread_t id[5];
    // 初始化互斥锁
    pthread_mutex_init(&block1, NULL);
    pthread_mutex_init(&block2, NULL);
    for (i = 0; i < 5; i++) {
        // 创建线程,传入火车索引作为参数
        pthread_create(&id[i], NULL, run, (void *)&i);
    }

    // 循环等待所有线程结束
    for (i = 0; i < 5; i++) {
        pthread_join(id[i], NULL);
    }

    // 清理互斥锁
    pthread_mutex_destroy(&block1);
    pthread_mutex_destroy(&block2);

    // 返回0表示正常退出
    return 0;
}

7.24

信号

创建一对父子进程,同时死循环

要求使用 ctrl+c 结束子进程的运行。父进程在回收完子进程的资源之后,输出 "资源回收完毕后" 也结束运行 

#include <myhead.h>
void handl(int signum)
{
    if (signum == SIGINT)
    {
        exit(0);
    }
    if (signum == SIGCHLD)
    {
        while (waitpid(-1,0,WNOHANG)!=-1);
        printf("资源回收完毕!\n");
        sleep(3);
        exit(0);
    }
}
int main(int argc, char const *argv[])
{
    signal(SIGCHLD, handl);
    int res = fork();
    if (res == 0)
    {
        while (1);

    }
    else if (res > 0)
    {
        signal(SIGINT, SIG_IGN);
        while (1)
            ;
    }
    else
    {
        perror("fork");
        return 1;
    }

    return 0;
}

 有名管道间通信

#include <myhead.h>
int main(int argc, char const *argv[])
{
    if (access("./mkfil0", F_OK) == -1)
    {
        mkfifo("./mkfifo", 0644);
    }
    int res = fork();
    if (res > 0) // 父进程写
    {
        int wfp = open("./mkfifo", O_RDWR);
        if (wfp == -1)
        {
            perror("open_wfd");
            exit(0);
        }
        while (1)
        {
            char buf[64] = {0};
            printf("请输入:");
            fgets(buf, 64, stdin);
            write(wfp, buf, sizeof(buf));
            usleep(1000);
        }
        close(wfp);
    }
    else if (res == 0) // 子进程读
    {
        int rfp = open("./mkfifo", O_RDWR);
        if (rfp == -1)
        {
            perror("open_rfd");
            exit(0);
        }
        while (1)
        {
            char buf[64] = {0};
            read(rfp, buf, sizeof(buf));
            printf("获取的数据为:%s\n", buf);
        }
        close(rfp);
    }
    else
    {
        perror("fork");
        return 1;
    }
    return 0;
}

无名管道

/* 创建一对父子进程,

父进程负责输入长方形的两条边长或者三角形的三边长

子进程负责计算长方形 或者 三角形的面积 */

#include <myhead.h>
int main(int argc, char const *argv[])
{
    int arr[2] = {0};
    int res = pipe(arr);
    if (res == -1)
    {
        perror("pipe");
        return 1;
    }
    res = fork();
    if (res > 0) // 父进程--写
    {
        close(arr[0]);
        while (1)
        {
            int buf[4] = {0};
            printf("请输入三边长或者两边长:");
            scanf("%d %d %d", &buf[0], &buf[1], &buf[2]);
            while (getchar() != 10)
                ;
            write(arr[1], buf, sizeof(buf));
            usleep(1000);
        }
    }
    else if (res == 0) // 子进程--读
    {
        close(arr[1]);
        while (1)
        {
            int flag = 0;
            int arg[4] = {0};
            int buf[4] = {0};
            read(arr[0], buf, sizeof(buf));
            if (buf[2] == 0)
            {
                printf("输入的长方形面积:%d*%d=%d\n", buf[0], buf[1], buf[0] * buf[1]);
            }
            else
            {
                int c = (buf[0] + buf[1] + buf[2]) / 2;
                int s = sqrt(c * (c - buf[0]) * (c - buf[1]) * (c - buf[2]));
                printf("输入的三角形面积:%d\n", s);
            }
        }
    }
    else
    {
        perror("fork");
        return 1;
    }

    return 0;
}

无名管道+进程替换

/* 创建2个.c 文件

一个.c 文件负责输入三角形或者长方形的数据

在第一个.c文件替换另一个.c 文件负责计算三角形 或者 长方形的面积

 */

写文件

#include <myhead.h>

int main(int argc, char const *argv[])
{
    int arr[2] = {0};
    int res = pipe(arr);
    if (res == -1)
    {
        perror("pipe");
        return 1;
    }
    res = fork();
    if (res > 0) // 父进程--写
    {
        close(arr[0]);
        while (1)
        {
            int buf[4] = {0};
            printf("请输入三边长或者两边长:");
            scanf("%d %d %d", &buf[0], &buf[1], &buf[2]);
            while (getchar() != 10)
                ;
            write(arr[1], buf, sizeof(buf));
            usleep(1000);
        }
    }
    else if (res == 0) // 子进程--读
    {
        execl("./child","child","NULL");
    }
    else
    {
        perror("fork");
        return 1;
    }

    return 0;
}

计算文件

#include <myhead.h>
int main(int argc, char const *argv[])
{
    close(4);
    while (1)
    {
        int flag = 0;
        int arg[4] = {0};
        int buf[4] = {0};
        read(3, buf, sizeof(buf));
        if (buf[2] == 0)
        {
            printf("输入的长方形面积:%d*%d=%d\n", buf[0], buf[1], buf[0] * buf[1]);
        }
        else
        {
            int c = (buf[0] + buf[1] + buf[2]) / 2;
            int s = sqrt(c * (c - buf[0]) * (c - buf[1]) * (c - buf[2]));
            printf("输入的三角形面积:%d\n", s);
        }
    }
    return 0;
}

有名管道+信号

 /* 有2个.c文件,每个.c文件都拥有一对父子进程,总共4个进程 A a B b

现在要求实现一个多米诺骨牌的效果:

按ctrl+c结束a进程的运行,a进程结束运行之前,

通过kill函数向b进程发送SIGINT信号,b进程死亡后,B进程回收b进程的资源后,

使用kill函数向A进程发送SIGTSTP信号后,结束运行。

A进程接受到B进程的SIGTSTP信号后,会后a进程的资源后也结束运行*/

A,a进程

#include <myhead.h>

int b_pid;
int A_pid;
void handle(int signum)
{
    if (signum == SIGINT)
    {
        printf("a进程死亡\n");
        sleep(1);
        kill(b_pid, signum);
        exit(0);
    }
    if (signum == SIGTSTP)
    {
        printf("A进程死亡\n");
        exit(0);
    }
}
int main(int argc, char const *argv[])
{
    if (access("./mkfilo", F_OK) == -1)
    {
        mkfifo("./mkfifo", 0644);
    }
    int fp = open("./mkfifo", O_RDWR);
    if (fp == -1)
    {
        perror("open");
        return 1;
    }

    int res = fork();
    if (res > 0) // A
    {
        signal(SIGINT, SIG_IGN);
        signal(SIGTSTP, handle);
        while (1)
            ;
    }
    else // a
    {
        
        char buf[20] = {0};
        read(fp, buf, 20);
        sscanf(buf, "%d", &b_pid);
        memset(buf, 0, 20);
        A_pid = getppid();
        sprintf(buf, "%d", A_pid);
        
        write(fp, buf, sizeof(buf));
        signal(SIGINT, handle);
        close(fp);
        
        while (1)
            ;
    }

    return 0;
}

B,b进程

#include <myhead.h>

int A_pid;
void handle(int signum)
{
    if (signum == SIGINT)
    {
        printf("b进程死亡\n");
        
        sleep(1);
        exit(0);
    }
}
int main(int argc, char const *argv[])
{
    if (access("./mkfilo", F_OK) == -1)
    {
        mkfifo("./mkfifo", 0644);
    }
    int fp = open("./mkfifo", O_RDWR);

    int res = fork();
    if (res > 0) // B
    {
        char buf[20] = {0};
        sprintf(buf, "%d", res);
        write(fp, buf, sizeof(buf));
        memset(buf, 0, 20);
        sleep(1);
        read(fp, buf, 20);
        close(fp);
        sscanf(buf, "%d", &A_pid);
        
        wait(0);
        printf("B结束运行\n");
        
        sleep(1);
        kill(A_pid, SIGTSTP);
        exit(0);
        while (1)
            ;
    }
    else // b
    {
        signal(SIGINT, handle);
        while (1)
            ;
    }

    return 0;
}

输出:

有名管道聊天

 /* 使用有名管道,实现2个进程之间的互相聊天 */

文件一

#include <myhead.h>
/* 使用有名管道,实现2个进程之间的互相聊天 */
int main(int argc, char const *argv[])
{
    if (access("./mkfilo", F_OK) == -1)
    {
        mkfifo("./mkfifo", 0644);
    }
    if (access("./mkfilo2", F_OK) == -1)
    {
        mkfifo("./mkfifo2", 0644);
    }
    int wfp = open("./mkfifo", O_RDWR);

    int rfp = open("./mkfifo2", O_RDONLY);
    if (wfp == -1 || rfp == -1)
    {
        perror("open_wfd");
        return 1;
    }
    int res = fork();
    if (res == 0)
    {
        while (1)
        {
            char buf[64] = {0};
            fgets(buf, 64, stdin);
            int len = strlen(buf);
            if (buf[len - 1] == '\n')
            {
                buf[len - 1] = '\0';
            }
            write(wfp, buf, sizeof(buf));
            usleep(1000);
        }
    }
    else
    {
        while (1)
        {
            char buf[64] = {0};
            read(rfp, buf, sizeof(buf));
            printf("对方发来消息:%s\n", buf);
        }
    }

    close(wfp);
    close(rfp);
    return 0;
}

文件二

#include <myhead.h>
/* 使用有名管道,实现2个进程之间的互相聊天 */
int main(int argc, char const *argv[])
{
    if (access("./mkfilo", F_OK) == -1)
    {
        mkfifo("./mkfifo", 0644);
    }
    if (access("./mkfilo2", F_OK) == -1)
    {
        mkfifo("./mkfifo2", 0644);
    }
    int rfp = open("./mkfifo", O_RDWR);
    int wfp = open("./mkfifo2", O_RDWR);

    if (wfp == -1 || rfp == -1)
    {
        perror("open");
        return 1;
    }

    int res = fork();
    if (res == 0)
    {
        while (1)
        {
            char buf[64] = {0};
            fgets(buf, 64, stdin);
            int len = strlen(buf);
            if (buf[len - 1] == '\n')
            {
                buf[len - 1] = '\0';
            }
            write(wfp, buf, sizeof(buf));
            usleep(1000);
        }
    }
    else
    {
        while (1)
        {
            char buf[64] = {0};


            read(rfp, buf, sizeof(buf));
            printf("对方发来消息:%s\n", buf);
        }
    }

    close(wfp);
    close(rfp);

    return 0;
}

输出:

父子进程判断回文字符串

/* 创建一对父子

父进程负责输入一串字符串

子进程负责判断这串字符串是否为回文字符串 */

#include <myhead.h>

int ptr(char buf[])
{
    int len=strlen(buf);
    char * p=buf;
    char * q=buf;
    q=q+len-1;
    for (int i = 0; i < len-1; i++)
    {
        if (*p==*q)
        {
            p++;
            q--;
        }else
        {
            return 0;
        }
    }
    return 1;

}
int main(int argc, char const *argv[])
{
    if (access("./mkfil0", F_OK) == -1)
    {
        mkfifo("./mkfifo", 0644);
    }
    int res = fork();
    if (res > 0) // 父进程写
    {
        int wfp = open("./mkfifo", O_RDWR);
        if (wfp == -1)
        {
            perror("open_wfd");
            exit(0);
        }
        while (1)
        {
            char buf[64] = {0};
            printf("\n请输入:");
            scanf("%s",buf);
            write(wfp, buf, sizeof(buf));
            usleep(1000);
        }
        close(wfp);
    }
    else if (res == 0) // 子进程读
    {
        int rfp = open("./mkfifo", O_RDWR);
        if (rfp == -1)
        {
            perror("open_rfd");
            exit(0);
        }
        while (1)
        {
            char buf[64] = {0};
            read(rfp, buf, sizeof(buf));
            printf("获取的数据为:%s\n", buf);
            if(ptr(buf))
            {
                printf("%s是回文字符串\n",buf);
            }
            else
            {
                printf("%s不是回文字符串\n",buf);
            }
        }
        close(rfp);
    }
    else
    {
        perror("fork");
        return 1;
    }
    return 0;
}

输出:

 生产者与消费者模型

/*

    有一个线程随机生产苹果和橘子

    每秒生产8个苹果或者5个橘子

    有4个消费者线程

    1,2号线程只消费苹果,1,2号线程每次消费5个苹果

    3,4号线程只消费橘子,3,4号线程每次消费3个橘子

*/

#include <myhead.h>

int apple = 0, orange = 0;
pthread_mutex_t m;
pthread_mutex_t m2;
pthread_cond_t c1;
pthread_cond_t c2;
/* 消费苹果的线程函数 */
void *run1(void *ptr)
{
    while (1)
    {
        /* 加锁以保护共享资源apple */
        pthread_mutex_lock(&m);
        /* 等待生产者信号 */
        pthread_cond_wait(&c1, &m);
        apple -= 5;
        printf("1号线程消耗了5个苹果,剩余%d个\n", apple);
        /* 解锁共享资源 */
        pthread_mutex_unlock(&m);
        sleep(2);
    }
}
/* 另一个消费苹果的线程函数 */
void *run2(void *ptr)
{
    while (1)
    {
        pthread_mutex_lock(&m);
        pthread_cond_wait(&c1, &m);
        apple -= 5;
        printf("2号线程消耗了5个苹果,剩余%d个\n", apple);
        pthread_mutex_unlock(&m);
        sleep(2);
    }
}
/* 消费橘子的线程函数 */
void *run3(void *ptr)
{
    while (1)
    {
        pthread_mutex_lock(&m2);
        pthread_cond_wait(&c2, &m2);
        orange -= 3;
        printf("3线程消耗了3个橘子,剩余%d个\n", orange);
        pthread_mutex_unlock(&m2);
        sleep(2);
    }
}
/* 另一个消费橘子的线程函数 */
void *run4(void *ptr)
{
    while (1)
    {
        pthread_mutex_lock(&m2);
        pthread_cond_wait(&c2, &m2);
        orange -= 3;
        printf("4号线程消耗了3个橘子,剩余%d个\n", orange);
        pthread_mutex_unlock(&m2);
        sleep(2);
    }
}

/* 主函数,扮演生产者角色 */
int main(int argc, char const *argv[])
{
    srand(time(0));
    pthread_mutex_init(&m, 0);
    pthread_mutex_init(&m2, 0);
    pthread_cond_init(&c1, 0);
    pthread_cond_init(&c2, 0);
    pthread_t id1, id2, id3, id4;
    pthread_create(&id1, 0, run1, 0);
    pthread_create(&id2, 0, run2, 0);
    pthread_create(&id3, 0, run3, 0);
    pthread_create(&id4, 0, run4, 0);
    while (1)
    {
        int flag = rand() % 2;
        pthread_mutex_lock(&m);
        pthread_mutex_lock(&m2);
        if (flag == 1)
        {
            apple += 8;
            printf("---------------------------------------------\n");
            printf("生产者了8个苹果,现有苹果%d,橘子%d个\n", apple, orange);
        }
        else
        {
            orange += 5;
            printf("---------------------------------------------\n");
            printf("生产者了5橘子,现有苹果%d,橘子%d个\n", apple, orange);
        }
        /* 当苹果数量足够时,通知消费者线程 */
        if (apple >= 5)
        {
            pthread_cond_signal(&c1);
        }
        /* 当橘子数量足够时,通知消费者线程 */
        if (orange >= 3)
        {
            pthread_cond_signal(&c2);
        }
        pthread_mutex_unlock(&m);
        pthread_mutex_unlock(&m2);
        sleep(1);
    }
    pthread_join(id1,0);
    pthread_join(id2,0);
    pthread_join(id3,0);
    pthread_join(id4,0);
    return 0;
}

输出:

 有一个盘子,盘子里面最多放3个苹果,5个橘子 2个生产者线程,一个每秒放1个苹果,另一个每秒2个橘子 放了苹果就不能放橘子,放了橘子就不能放苹果 2个消费者线程,1号消费者线程每秒消费2个苹果,2号消费者线程,每秒消费3个橘子

#include <myhead.h>
/* 全局变量定义,用于存储苹果和橘子的数量 */
int apple = 0, orange = 0;
/* 定义两个互斥锁,用于保护苹果和橘子数量的访问 */
pthread_mutex_t m;
pthread_mutex_t m2;
/* 定义两个条件变量,用于线程间的通信 */
pthread_cond_t c;
pthread_cond_t c2;

/* run1 函数是消费者线程1的入口函数 */
void *run1(void *ptr)
{
    while (1)
    {
        /* 加锁以保护共享资源 */
        pthread_mutex_lock(&m);
        /* 等待条件变量满足 */
        pthread_cond_wait(&c, &m);
        /* 消费苹果 */
        apple -= 2;
        printf("1号线程消耗了2个苹果,剩余%d个\n", apple);
        /* 释放锁 */
        pthread_mutex_unlock(&m);
        /* 暂停1秒,模拟消费过程 */
        sleep(1);
    }
}

/* run2 函数是消费者线程2的入口函数 */
void *run2(void *ptr)
{
    while (1)
    {
        /* 加锁以保护共享资源 */
        pthread_mutex_lock(&m2);
        /* 等待条件变量满足 */
        pthread_cond_wait(&c2, &m2);
        /* 消费橘子 */
        orange -= 3;
        printf("2线程消耗了3个橘子,剩余%d个\n", orange);
        /* 释放锁 */
        pthread_mutex_unlock(&m2);
        /* 暂停1秒,模拟消费过程 */
        sleep(1);
    }
}

/* 主函数是程序的入口点 */
int main(int argc, char const *argv[])
{
    /* 初始化随机数种子 */
    srand(time(0));
    /* 初始化互斥锁 */
    pthread_mutex_init(&m, 0);
    pthread_mutex_init(&m2, 0);
    /* 初始化条件变量 */
    pthread_cond_init(&c, 0);
    pthread_cond_init(&c2, 0);

    /* 创建两个线程 */
    pthread_t id1, id2;
    pthread_create(&id1, 0, run1, 0);
    pthread_create(&id2, 0, run2, 0);

    while (1)
    {
        /* 随机决定生产苹果或橘子 */
        int flag = rand() % 2;

        /* 加锁以保护共享资源 */
        pthread_mutex_lock(&m);
        pthread_mutex_lock(&m2);

        /* 根据当前库存决定是否生产苹果或橘子 */
        if (apple >= 3 && orange <= 4)
        {
            flag = 0;
        }
        else if (apple <= 3 && orange >= 5)
        {
            flag = 1;
        }

        /* 根据flag决定实际生产什么 */
        if (flag == 1)
        {
            if (apple >= 3)
            {
                continue;
            }
            apple += 1;
            printf("---------------------------------------------\n");
            printf("生产者了1个苹果,现有苹果%d,橘子%d个\n", apple, orange);
        }
        else
        {
            if (orange >= 4)
            {
                continue;
            }
            orange += 2;
            printf("---------------------------------------------\n");
            printf("生产者了2橘子,现有苹果%d,橘子%d个\n", apple, orange);
        }

        /* 如果苹果数量足够,通知消费者线程1 */
        /* 当苹果数量足够时,通知消费者线程 */
        if (apple >= 2)
        {
            pthread_cond_signal(&c);
        }
        /* 如果橘子数量足够,通知消费者线程2 */
        /* 当橘子数量足够时,通知消费者线程 */
        if (orange >= 3)
        {
            pthread_cond_signal(&c2);
        }

        /* 释放锁 */
        pthread_mutex_unlock(&m);
        pthread_mutex_unlock(&m2);
        /* 暂停1秒,模拟生产过程 */
        sleep(1);
    }

    /* 等待线程结束 */
    pthread_join(id1, 0);
    pthread_join(id2, 0);
    return 0;
}

 C++

8.6

自己封装一个矩形类(Rect),拥有私有属性:宽度(width)、高度(height),

定义公有成员函数:

初始化函数:void init(int w, int h)

更改宽度的函数:set_w(int w)

更改高度的函数:set_h(int h)

输出该矩形的周长和面积函数:void show()

#include <iostream>

using namespace std;
class Rect{
private:
    int  width;
    int height;

public:
void init(int w, int h);
void set_w(int w);
void set_h(int h);
void show();
};

void Rect::init(int w, int h)
{
    this->width=w;
    this->height=h;
}
void Rect::set_w(int w)
{
    this->width=w;
}
void Rect::set_h(int h)
{
    this->height=h;
}
void Rect::show()
{
    cout << "面积为" << width*height << endl;
    cout << "周长为" << 2*(width+height) << endl;
}
int main()
{
    Rect r1;
    r1.init(10,20);
    r1.show();
    r1.set_h(5);
    r1.set_w(5);
    r1.show();
    return 0;
}

8.7

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

#include <iostream>

using namespace std;
class Per
{
private:
    string name;
    int age;
    double *tall;
    double *weight;
public:
    Per()//无参
    {
        tall=nullptr;
        weight=nullptr;
        cout << "Per::无参数构造类型" << endl;
    }
    Per(string name,int age,double tall,double weight):name(name),age(age),tall(new double (tall)), weight(new double (weight))   //有参构造函数
    {
        cout << "Per::有参构造函数" << endl;
    }
    ~Per()//析构
    {
        delete tall;
        delete weight;
        cout << "Per::析构函数" <<endl;
    }
    Per (const Per &other):name(other.name),age(other.age),tall(new double (*other.tall)),weight(new double (*other.weight))//拷贝构造函数
    {
        cout << "Per::拷贝构造函数" << endl;
    }
    void show ()//打印信息
    {
        cout << "name  = " << name  <<endl;
        cout << "age  = " << age  <<endl;
        cout << "tall  = " << *tall  <<endl;
        cout << "weight  = " << *weight  <<endl;
    }
};
class Stu
{
private:
    double score;
    Per p1;
public:
    Stu()//无参
    {
        cout << "Stu::无参构造类型" << endl;
    }
    Stu(double score,string name,int age,double tall,double weight):score(score),p1(name,age,tall,weight)//有参
    {
         cout << "Stu::有参构造类型" << endl;
    }
    ~Stu()//析构函数
    {
        p1.~Per();
        cout << "Stu::析构函数" <<endl;
    }
    Stu(const Stu &sother ):score(sother.score),p1(sother.p1) //拷贝构造函数
    {

        cout<< "Stu::拷贝构造函数" << endl;
    }
    void show()//打印信息
    {
        cout << "score = " << score << endl;
        p1.show();
    }
};
int main()
{
    Per p1("陶单单",23,184.99,149.99);
    cout << "p1:" <<endl;
    p1.show();
    Stu s1(99.9,"黄姑娘",27,174.99,140);
    cout << "s1:" <<endl;
    s1.show();
    Stu s2(s1);
    cout << "s2:" <<endl;
    s2.show();
    return 0;
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值