C语言

开发工具选择

自行下载 阿里云盘获取

语法

基础部分

程序框架
  • c语言基本框架

    1
    2
    3
    4
    5
    6
    #include <stdio.h>
    int main()
    {

    return 0;
    }
  • 输出

    1
    printf("双引号的内容将会被原位输出");
  • 基本运算

    1
    2
    3
    4
    5
    6
    #include <stdio.h>
    int main()
    {
    printf("30+91=%d", 30 + 91);
    return 0;
    }
  • 输入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>
    int main()
    {
    printf("请输入两个整数: ");
    int num1,
    num2;

    scanf("%d %d", &num1, &num2);

    printf("输入整数的和为: %d + %d = %d", num1, num2, num1 + num2);

    return 0;
    }
  • 表达式

    1
    一个表达式是一系列运算符和算子的组合,用来计算一个值。
  • 计算时间差

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <stdio.h>
    int main()
    {
    // 计算时间差
    int hour1,
    minute1;
    int hour2,
    minute2;

    scanf("%d %d", &hour1, &minute1);
    scanf("%d %d", &hour2, &minute2);

    int t1 = hour1 * 60 + minute1; // 2*60+20 = 140 min
    int t2 = hour2 * 60 + minute2; // 3*60+20 = 200 min
    int t = t2 - t1; // 200 - 140 = 60 min 60/60=1h,60%60=0min

    printf("时间差是: %d小时%d分", t / 60, t % 60); // 1小时0
    return 0;
    }
  • 运算符优先级

    优先级 运算符 运算 结合关系 举例
    1 + 单目不变 自右向左 a*+b
    1 - 单目取负 自右向左 a*-b
    2 * 自左向右 a*b
    2 / 自左向右 a/b
    2 % 取余 自左向右 a%b
    3 + 自左向右 a+b
    3 - 自左向右 a-b
    4 = 赋值 自右向左 a=b
  • 交换两个变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include <stdio.h>
    int main()
    {
    // 计算时间差
    int a = 10;
    int b = 20;
    int temp = 0;

    printf("交换前: a=%d b=%d\n", a, b);

    // 交换两个数
    temp = a;
    a = b;
    b = temp;

    printf("交换后: a=%d b=%d", a, b);
    return 0;
    }
除法与取模运算符
  • 除法/ 的运算结果对象的数据类型有关,两个数都是int,则商就是int,若商有小数,则截取小数部分,被除数和除数中只要有一个或两个都是浮点型数据,则商也是浮点型,不截取小数部分

    1
    2
    16 / 5 == 3
    16 / 5.0 == 3.200000
  • 取余% 的运算必须是整数,结果是整除后的数,其余数的符号与被除数相同

    1
    2
    3
    13 % 3 == 1 
    13 % -3 == 1
    -13 % 3 == -1
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
//
// Created by coder-itl on 2021/9/27.
//

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

/* 方式一 */
enum Boolean {
FALSE = 0, TRUE
};

int main() {
/* 方式二 */
/* 使用 1== true */
int boolR = 1;
if (boolR) {
printf("result is true");
}

/* 方式三 */
bool boolH = true;
if (boolH == true) {
printf("BoolH is true");
}

return 0;
}
符号常量
  • 基本使用

    1
    2
    // 定义字符常量
    #define PI 3.1415926;
数组与函数相关练习
  • 插入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    【问题描述】编写程序,向有序序列中插入一个元素。设一个大小为10的一维数组中保存了一个有9个元素的非递减有序的整数序列,从键盘输入一个整数,将该整数插入到有序序列中,插入之后序列仍保持有序。输出插入前的序列和插入后的序列。

    说明:有序序列通过键盘输入得到,且输入过程通过程序控制,只能输入非递减序列,若输入过程中,某元素比前一元素小,则该元素输入视为无效,需要重新输入此元素。
    【输入形式】输入非递减的9个整数,输入待插整数
    【输出形式】插入前的序列和插入后的序列


    【样例输入】

    3 3 4 5 3 7 8 10 12 15

    6
    【样例输出】

    Before:3 3 4 5 7 8 10 12 15

    After:3 3 4 5 6 7 8 10 12 15
    【样例说明】

    输入有序序列过程中,第5个整数3因小于前一个整数5,为无效输入,重新输入第5个整数为7

    2行输入待插入整数为6

    输出时,每个数据占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
28
29
30
31
32
33
34
//
// Created by coder-itl on 2021/9/29.
//
#include "stdio.h"
#include "malloc.h"

int main() {
int i;
/* 输入长度 */
int length;
/* 获取输入 */
printf("请输入数组长度: \n");
scanf("%d", &length);
/* 动态分配 */
int *p = (int *) malloc(sizeof(int) * length);
/* 定义动态数组 */
int array[length];
/* 对数组添加数据 */
printf("请输入数组元素: \n");
for (i = 0; i < length; i++) {
/* 向数组输入元素 */
scanf("%d", &array[i]);
}
/* 输出数组内容 */
for (i = 0; i < length; i++) {
/* 以左对齐 4 列宽输出 */
printf("%-4d", array[i]);
}
/* 把 p 所代表的动态分配的内存释放 */
free(p);

return 0;
}

1
2
3
4
5
总结 malloc 使用要点:
1: 添加头文件 #include "malloc.h"
2: malloc 函数只有一个形参,并且必须是整型
3: malloc 函数只能返回第一个字节的地址
4: free(xx) 操作
指针
  • 就是保存地址的变量

  • 语法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    #include <stdio.h>

    int main() {
    /* 定义变量 i */
    int i;
    /* 定义指针变量 *p,并将 i 的地址值交给 p */
    int *p = &i; /* p 不是 i,更准确的说: 修改 p 的值不影响 i 的值,修改 i 的值也不会改变 i */
    /* 定义指针 *n,整形变量 q(而q并非是 指针变量) */
    int *n, q;
    return 0;
    }
    1
    2
    3
    4
    5
    6
    7
     /* p 不是 i,更准确的说: 修改 p 的值不影响 i 的值,修改 i 的值也不会改变 i */

    如果一个指针变量指向了某个普通变量,则 *指针变量 就完全等同于 普通变量
    例子:
    如果 p 是个指针变量, 并且存放了普通变量 i 的地址,则 p 指向了普通变量 i,*p 就完全等同于 i
    或者说: 在所有出现 *p 的地方都可以替换成 i
    在所有出现 i 的地方都可以替换成 *p
  • 通过指针交换两个变量的值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //
    // Created by coder-itl on 2021/9/26.
    //
    #include "stdio.h"

    void swap(int *pa, int *pb) {
    int t;
    t = *pa;
    *pa = *pb;
    *pb = t;
    };

    int main() {
    int a = 10, b = 20;

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

    return 0;
    }


  • * 号的三重含义

    1
    2
    3
    4
    5
    6
    1. 乘法
    2. 定义指针变量
    3. 指针运算符
    该运算符放在已经定义好的指针变量的前面,
    如果 p 是一个已经定义好的指针变量
    则 *p 表示 以 p 的内容为地址的变量
  • 变量的值是内存的地址

    • 普通变量的值是实际的值
    • 指针变量的值是具有实际值的变量的地址
  • 指针作为参数传递

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

    /* 输入数组的函数声明 */
    int *inputArray();

    /* 排序数组函数声明 */
    int *sortArray(int *p);

    /* 输出数组函数声明 */
    void printfArray(int *p);

    // TODO: 1. 缺少倒序排序 输出格式问题
    int main() {
    int *p, *q;

    p = inputArray();

    printf("Before sort:");
    printfArray(p);

    q = sortArray(p);
    printf("\nAfter sort:");
    printfArray(q);

    return 0;
    }


    int *inputArray() {
    /* 数组容量和变量 i */
    int i, num;
    scanf("%d", &num); /* maloc() */
    /* 定义整形数组 */
    static int array[5];

    /* 动态获取数组长度 */
    int length = sizeof(array) / sizeof(array[0]);

    for (i = 0; i < length; i++) {
    scanf("%d", &array[i]);
    }
    return array;
    }

    int *sortArray(int *p) {
    int i, j;
    for (i = 0; i < 5 - 1; i++) {
    for (j = 0; j < 5 - 1 - i; j++) {
    if (p[j] > p[j + 1]) {
    int temp = p[j];
    p[j] = p[j + 1];
    p[j + 1] = temp;
    }
    }
    }
    return p;
    }

    void printfArray(int *p) {
    int i;
    for (i = 0; i < 5; ++i) {
    printf("%-4d", *(p + i));
    }
    }
深入了解指针
  • 使用:

    point01.png

    point02.png

    1
    2
    3
    4
    5
    6
    疑问: *p 和 p 选取的时机问题?

    如何通过被调函数修改主调函数普通变量的地址:
    1. 实参必须为该普通变量的地址
    2. 形参必须为指针变量
    3. 在被调函数中通过 *形参名 = ... 的方式就可以修改主调函数相关变量的值

    Point03-queation.png

指针与一维数组的关系
  • 指针和数组

    1
    一维数组名: 一维数组名是一个指针常量,它存放的是一维数组第一个元素的地址
  • 下标和指针的关系

    1
    如果 P 是个指针变量,则 p[i] 永远等价于 *(p+1)
  • 确定一个一维数组需要几个参数[如果一个函数要处理一个一维数组,则需要接受该数组的那些信息?]

    1
    2
    1. 数组名 
    2. 数组长度
  • 指针变量的运算

    1
    2
    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
    //
    // Created by coder-itl on 2021/10/3.
    //

    #include "stdio.h"

    /* 形参含义:
    * "*p" = 数组名
    * length: 数组长度
    * */
    void printfArray(int *p, int length);

    int main() {
    int arrayA[] = {1, 3, 5, 7, 10};
    int arrayB[] = {2, 3, 6, 7, 10};
    int arrayC[] = {4, 1, 5, 7, 10};
    /* 将数组强制转换为 (int *) 类型 */
    printfArray((int *) &arrayC, 5);

    return 0;
    }


    void printfArray(int *p, int length) {
    int i;
    for (i = 0; i < length; i++) {
    printf("%d ", p[i]);
    }

    }
结构体
  • 定义

    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

    //
    // Created by coder-itl on 2021/9/26.
    //

    #include <stdio.h>
    /* 布尔值的库 */
    #include <stdbool.h>
    /* 字符串的库 */
    #include "string.h"

    struct stuBirthday {
    /* 年 */
    int year;
    /* 月 */
    int month;
    /* 日 */
    int day;
    };

    struct StuScore {
    /* 平时成绩 */
    int normalGrades;
    /* 实验成绩 */
    int experimentalGrades;
    /* 期末成绩 */
    int finalGrades;
    /* 总评成绩 */
    int generalCommentGrades;
    };

    struct Members {
    /* 限制学号 为 7 位数 */
    int stuNo;
    /* 学生姓名 限制长度为: 4*/
    char stuName[9];
    /* 学生出生日期 格式: 年//日 */
    struct stuBirthday birthday;
    /* 总评成绩=平时成绩*0.2+实验成绩*0.3+期末成绩*0.5 */
    struct StuScore stuScore;
    };


    int main() {

    int num, i;

    /*
    * 结构体赋值:
    * 1. 点域"." 的方式
    * 2. 地址: ->
    * */
    /* 输入数量 */
    scanf("%d", &num);
    struct Members members[num];
    for (i = 0; i < num; i++) {
    /* 结构体赋值 */
    scanf("%d", &members[i].stuNo);

    /* 结构体字符数组元素的输入赋值 */
    scanf("%s", members[i].stuName);

    /* 输入年月日 */
    scanf("%d %d %d",
    /* 年 */
    &members[i].birthday.year,
    /* 月 */
    &members[i].birthday.month,
    /* 日 */
    &members[i].birthday.day);

    /* 输入成绩 */
    scanf("%d %d %d",
    /* 输入学生的平时成绩 */
    &members[i].stuScore.normalGrades,
    /* 输入学生的实验成绩 */
    &members[i].stuScore.experimentalGrades,
    /* 输入学生的期末成绩 */
    &members[i].stuScore.finalGrades
    );

    }

    printf("%-10s%-10s%-12s%-4s%-4s%-4s%-4s\n", "num", "name", "birthday", "s1", "s2", "s3", "sum");
    /* 结构体输出 */
    for (i = 0; i < num; i++) {
    /* 总评成绩 = 平时成绩*0.2+实验成绩*0.3+期末成绩*0.5 */
    members[i].stuScore.generalCommentGrades =
    (members[i].stuScore.normalGrades * 0.2) + (members[i].stuScore.experimentalGrades * 0.3) +
    (members[i].stuScore.finalGrades * 0.5);
    /* 学号10列列宽,左对齐;
    * 姓名10列列宽,左对齐;
    * 出生日期的年份原样输出,月份为2列列宽右对齐,日为4列列宽左对齐;
    * 平时成绩、实验成绩、期末成绩和总评成绩均为4列列宽,左对齐
    * */
    printf("%-10d%-10s%-4d/%2d/%-4d%-4d%-4d%-4d%-4d",
    /* 输出学号 */
    members[i].stuNo,
    /* 输出学生姓名 */
    members[i].stuName,
    /* 输出学生出生的年分 */
    members[i].birthday.year,
    /* 输出学生出生的月分 */
    members[i].birthday.month,
    /* 输出学生出生的 天数 */
    members[i].birthday.day,
    /* 平时成绩 */
    members[i].stuScore.normalGrades,
    /* 实验成绩 */
    members[i].stuScore.experimentalGrades,
    /* 期末成绩 */
    members[i].stuScore.finalGrades,
    /* 总评成绩= 平时成绩*0.2 + 实验成绩*0.3 + 期末成绩*0.5 */
    members[i].stuScore.generalCommentGrades
    );
    /* 完成一个学生信息后换行 */
    printf("\n");
    }
    return 0;
    }

C语言练习题