C语言快速复习指南

序言

本文为作者整理c语言复习笔记所得,旨在能快速巩固、回忆c语言的基础知识。因此,本文只适合初学者入门和因太久未接触导致的遗忘之人。

                                                                                        Ethan X.

一、C程序的基本结构

(一)、基础概念

让我们从C程序的基本结构开始。一个基础的C程序包含以下元素:

  1. 预处理器指令:预处理器指令是在C程序编译之前进行处理的指令。这些指令都以#符号开始。最常见的预处理器指令是#include,用于包含其他文件或库。例如,#include <stdio.h>会包含C语言的标准输入输出库。
#include <stdio.h>
  1. 函数:在C程序中,代码是由函数构成的。函数是一段可以被其他部分的代码调用的代码块。C语言程序至少有一个函数,即main()函数,这是程序执行的入口点。
int main() {
   // Your code goes here
}


main函数返回一个整数,通常用return 0;表示程序成功执行。return 0;语句是可选的,如果没有写,编译器会自动添加。

int main() {
   // Your code goes here
   return 0;
}
  1. 函数体:大括号{}中的代码称为函数体。在main()函数中,你的所有代码都将在这里编写。

每一段C代码都由一个或多个函数组成,每个函数完成一个特定的任务。代码的执行从main()函数开始,这是C语言程序的入口点。

在这个基本结构中,我们可以添加更多的函数、变量和其他元素,如控制结构、数组、指针、结构体等,这都将在复习的后续部分介绍。

记住,C语言使用分号;来结束一个语句,这是C语言的重要语法规则。如果忘记在语句后添加分号,编译器会报错。

以上就是C程序的基本结构,希望对你有所帮助。

(二)、巩固练习

1、编写一个简单的"Hello, World!"程序。

一个简单的 “Hello, World!” 程序在C语言中的写法如下:

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

这个程序的解释如下:

  • #include <stdio.h>:这是预处理器指令,告诉C编译器在实际编译之前包含标准输入输出头文件(stdio.h)。
  • int main():这是主函数,程序从这里开始执行。
  • printf("Hello, World!\n");printf函数用于在屏幕上打印输出。这里,它打印出 “Hello, World!”。
  • \n 是一个特殊的字符,代表换行,使得输出内容不会在一行中。
  • return 0;:这是主函数的返回语句。主函数返回0,表示程序成功结束。

你需要把这段代码保存到一个 .c 文件中,然后使用C编译器(如gcc)来编译和运行它。如果一切正确,它会在屏幕上打印出 “Hello, World!”。

2、试着使用不同的数据类型(例如int、float、char)并输出它们。

在这个练习中,你将创建几个不同类型的变量,并使用printf函数来输出它们。这是一个例子:

#include <stdio.h>

int main() {
    int integerVar = 100;
    float floatingVar = 331.79;
    char charVar = 'G';

    printf("整型变量的值为 %d\n", integerVar);
    printf("浮点型变量的值为 %.2f\n", floatingVar);
    printf("字符型变量的值为 %c\n", charVar);

    return 0;
}

这个程序的解释如下:

  • 我们首先定义了三个变量:一个int(整型)变量integerVar,一个float(浮点型)变量floatingVar,以及一个char(字符型)变量charVar
  • 然后我们使用printf函数来输出这些变量的值。在printf中,我们使用格式化字符串来指定输出的格式。%d用于int,%.2f用于float,并且我们限定了小数点后的位数为2,%c用于char。
  • 注意到,我们在printf函数中使用逗号来分隔格式化字符串和我们要输出的变量。

当你运行这个程序,你会在控制台看到这些变量的值。你也可以尝试更改这些变量的值,或者添加更多的变量,来看看会发生什么。

二、注释

(一)、基础概念

在编程中,注释用于解释代码的功能,以帮助其他人(或者你自己)理解代码的工作方式。注释对于编写清晰、可读性强的代码至关重要。在C语言中,有两种方式可以添加注释:

  1. 单行注释:单行注释是通过//来创建的。//后面的所有内容都会被视为注释,只到这一行结束。
// 这是一个单行注释
int a = 10; // 这也是一个单行注释


在这个例子中,int a = 10;是一个语句,而// 这也是一个单行注释是一个注释。在这行中的//之后的所有内容都会被视为注释。

  1. 多行注释:多行注释是通过/**/来创建的。这两个标记之间的所有内容都会被视为注释。
/* 这是一个
   多行
   注释 */


在这个例子中,/**/之间的所有内容都是注释。

在C语言中,注释是被编译器忽略的,所以你可以在注释中写任何你想写的内容,而不会影响到你的程序。使用注释来解释你的代码的功能和工作方式,能让你的代码更易于理解和维护。

以上就是C语言中关于注释的内容,如果你有任何问题,或者想要讨论其他的部分,欢迎随时告诉我。

(二)、巩固练习

1、在你的代码中添加适当的单行和多行注释。

这个练习的目标是在你的C代码中添加注释。注释是一种让你的代码更易于理解和维护的有效方式。C语言中有两种注释,单行注释和多行注释。

单行注释以 // 开头,从 // 开始,直到这一行的末尾,所有内容都会被编译器忽略。

多行注释以 /* 开头,并以 */ 结束。这种类型的注释可以跨越多行,/**/ 之间的所有内容都会被编译器忽略。

下面是一个例子:

#include <stdio.h>

int main() {
    // 这是一个单行注释

    /* 这是一个
       多行注释 */

    printf("Hello, World!\n");  // 在行尾添加注释

    return 0;
}

在这个程序中,我们在不同位置添加了注释:在一行的开始,跨越多行,以及在一行的结尾。

你的任务是,将这个代码复制到你的开发环境中,尝试添加、修改和删除注释,看看它们是如何影响(或者说不影响)程序输出的。

三、数据类型

(一)、基础概念

在C语言中,数据类型决定了变量或函数可以操作的数据的种类。以下是C语言中主要的数据类型:

  1. 整数类型:包括 intshortlonglong long,用于存储整数值。这些类型的大小和精度可能取决于特定的系统和编译器实现。
  2. 浮点类型:包括 floatdouble,用于存储小数值,double 提供的精度高于 float
  3. 字符类型char 类型用于存储单个字符。
  4. 布尔类型:C99开始,C语言支持 _Bool 或者通过包含 stdbool.h 文件来支持 bool,用于存储逻辑值(truefalse)。
  5. 复合类型:包括数组、结构体、联合体和枚举类型。
  6. 派生类型:包括指针类型、数组类型、结构类型、共用体类型和函数类型。
  7. 空类型void 类型表明没有可用的值。它常常用在函数返回值为空的情况下。

这些类型都有它们各自的大小和值的范围,这些都是由编译器和用于编译的特定硬件决定的。

当你声明一个变量时,必须要给出它的类型,例如:

int myNumber;
float myFloat;
char myChar;

你也可以在声明时初始化变量:

int myNumber = 10;
float myFloat = 3.14;
char myChar = 'a';

以上就是C语言中的数据类型的基本介绍。如果你有任何问题,或者想要讨论其他的部分,欢迎随时告诉我。

(二)、巩固练习

1、使用各种数据类型(如整型、浮点型、字符型)创建变量,并试图修改和输出它们的值。

在这个练习中,你需要创建并修改不同类型的变量,并使用printf函数输出它们。以下是一个示例:

#include <stdio.h>

int main() {
    int integerVar = 100;
    float floatingVar = 331.79;
    char charVar = 'G';

    printf("初始值: 整型变量 = %d, 浮点型变量 = %.2f, 字符型变量 = %c\n", integerVar, floatingVar, charVar);

    // 修改变量的值
    integerVar = 200;
    floatingVar = 500.32;
    charVar = 'M';

    printf("修改后的值: 整型变量 = %d, 浮点型变量 = %.2f, 字符型变量 = %c\n", integerVar, floatingVar, charVar);

    return 0;
}

在这个程序中:

  1. 我们首先定义了三个变量:一个int类型的integerVar,一个float类型的floatingVar,和一个char类型的charVar。然后我们打印了这些变量的初始值。
  2. 接着,我们改变了这些变量的值,然后再次打印它们的值。

你可以复制这个代码,尝试更改变量的初始值和后来的值,看看程序是如何响应的。你也可以尝试添加更多类型的变量,比如双精度浮点型(double)和长整型(long)。

四、变量

(一)、基础概念

在C语言中,变量是用来存储数据的标识符(即名称)。声明变量时,你需要指定一个数据类型,这将决定变量可以存储的数据类型、大小以及数值范围。

以下是C语言变量声明的一般形式:

type variable_list;

在这里,type 必须是一个有效的C数据类型,variable_list 可以包含一个或多个以逗号分隔的标识符名称。例如:

int i, j, k;
char c, ch;
float f, salary;
double d;

变量可以在声明的时候被初始化(指定一个初始值)。它们被初始化的值必须与变量声明的类型兼容。这里有一些初始化变量的例子:

int i = 100;
float f = 3.14;
char ch = 'a';

以下是在声明时初始化多个变量的示例:

int i = 5, j = 6, k = 7;
char c = 'C', ch = 'H';

变量在声明后可以被赋值,例如:

int i; // 声明
i = 10; // 赋值

也可以在一行内完成变量的声明和赋值:

int i = 10; // 声明并赋值

这就是C语言中关于变量的基本信息。如果你有任何问题,或者想要讨论其他的部分,欢迎随时告诉我。

五、控制结构

(一)、基础概念

在C语言中,我们有几种控制结构可以控制程序流程。主要有三种控制结构:顺序结构、选择结构和循环结构。

  1. 顺序结构:这是最基本的控制结构。它按照程序代码的顺序执行指令。
  2. 选择结构:选择结构允许你根据条件选择执行特定的代码块。在C语言中,我们主要使用ifif...elseswitch语句来进行选择。
// if 语句
if(condition) {
   // 当条件为真时执行的代码
}

// if...else 语句
if(condition) {
   // 当条件为真时执行的代码
} else {
   // 当条件为假时执行的代码
}

// switch 语句
switch(expression) {
   case constant1:
      // 当表达式等于constant1时执行的代码
      break;
   case constant2:
      // 当表达式等于constant2时执行的代码
      break;
   // 可以有任意数量的 case 语句
   default: 
      // 当所有的 case 都不匹配时执行的代码
}
  1. 循环结构:循环结构允许你多次执行一段代码。在C语言中,我们主要使用forwhiledo...while循环。
// for 循环
for(initialization; condition; increment/decrement) {
   // 当条件为真时重复执行的代码
}

// while 循环
while(condition) {
   // 当条件为真时重复执行的代码
}

// do...while 循环
do {
   // 代码块
} while(condition); // 当条件为真时重复执行的代码

以上就是C语言中关于控制结构的基本信息。如果你有任何问题,或者想要讨论其他的部分,欢迎随时告诉我。

(二)、巩固练习

1、编写使用if、else if、else语句的程序。

在这个练习中,你将学习如何使用 ifelse ifelse 语句来控制程序的流程。以下是一个示例:

#include <stdio.h>

int main() {
    int score = 85;

    if (score >= 90) {
        printf("你的等级是A。\n");
    } else if (score >= 80) {
        printf("你的等级是B。\n");
    } else if (score >= 70) {
        printf("你的等级是C。\n");
    } else if (score >= 60) {
        printf("你的等级是D。\n");
    } else {
        printf("你的等级是F。\n");
    }

    return 0;
}

这个程序首先定义了一个名为 score 的变量,然后使用一系列的 ifelse ifelse 语句来检查 score 的值,并根据 score 的值输出相应的等级。

你可以更改 score 的值,看看程序的输出是如何改变的。你也可以尝试添加更多的条件判断,或者改变现有条件判断的顺序,看看会发生什么。

2、编写一个for循环来打印出一系列数字。

在这个练习中,你将使用for循环来打印一系列的数字。以下是一个示例:

#include <stdio.h>

int main() {
    int i;
    for(i = 0; i < 10; i++) {
        printf("%d\n", i);
    }
    return 0;
}

在这个程序中,我们定义了一个变量 i,然后使用for循环使 i 从0增加到9。在每次循环中,我们都打印 i 的值。

for循环的语法包括三部分:

  1. 初始化语句(i = 0):在循环开始前执行,通常用于初始化计数器。
  2. 条件语句(i < 10):在每次循环开始时检查,如果为真,则执行循环体,如果为假,则退出循环。
  3. 更新语句(i++):在每次循环结束时执行,通常用于更新计数器。

你可以更改循环的初始化语句,条件语句和更新语句,看看它们是如何影响循环的。例如,你可以尝试将循环计数到100,或者以2的步长进行计数。

3、使用while和do-while循环打印出一系列数字。

这个练习将使用 whiledo-while 循环来打印一系列的数字。以下是一个示例:

使用 while 循环:

#include <stdio.h>

int main() {
    int i = 0;

    while(i < 10) {
        printf("%d\n", i);
        i++;
    }

    return 0;
}

在这个程序中,我们定义了一个变量 i,然后使用 while 循环使 i 从0增加到9。在每次循环中,我们都打印 i 的值。

使用 do-while 循环:

#include <stdio.h>

int main() {
    int i = 0;

    do {
        printf("%d\n", i);
        i++;
    } while(i < 10);

    return 0;
}

这个 do-while 循环的功能和 while 循环的功能基本相同。主要的区别在于,do-while 循环会先执行一次循环体,然后再检查条件。这意味着,即使条件一开始就是假的,循环体也至少会被执行一次。

你可以更改循环的条件和更新语句,看看它们是如何影响循环的。例如,你可以尝试将循环计数到100,或者以2的步长进行计数。

六、函数

(一)、基础概念

在C语言中,函数是一组被组织起来进行特定任务的语句集。所有的C程序都有至少一个函数,也就是主函数 main()。函数可以提高代码的模块性和代码的重用性。

函数的定义

一个C语言的函数由一个函数头和一个函数体组成。以下是C语言中函数的格式:

return_type function_name( parameter list ) {
   body of the function
}
  • return_type:这定义了函数返回的类型。这可以是任何数据类型。
  • function_name:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
  • parameters:参数就像是占位符。当函数被调用时,你传递一个值给参数,这个值被称为实际参数。参数列表包括参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
  • function body:函数体包含一组定义函数任务的语句。

例如:

int add(int a, int b) { // 定义函数 add
   int sum;
   sum = a + b;
   return sum;  // 返回 sum
}

函数的调用

当我们在需要的时候,可以通过函数的名字来调用函数。例如:

int result = add(10, 20);  // 调用函数 add

在这个例子中,函数 add 被调用,参数 1020 被传递给函数,函数的返回值被赋值给变量 result

以上就是C语言中关于函数的基本信息。如果你有任何问题,或者想要讨论其他的部分,欢迎随时告诉我。

(二)、巩固练习

1、创建一个函数,将两个数字作为输入,返回它们的和。

这个练习中,你需要创建一个函数,接受两个参数,并返回它们的和。以下是一个示例:

#include <stdio.h>

// 定义函数
int add(int num1, int num2) {
    int sum;
    sum = num1 + num2;
    return sum;
}

int main() {
    int result;
    
    // 调用函数
    result = add(10, 20);
    printf("10 + 20 = %d\n", result);
    
    return 0;
}

在这个程序中:

  • 我们首先定义了一个名为 add 的函数。这个函数接受两个 int 类型的参数 num1num2,计算它们的和,并返回结果。
  • main 函数中,我们调用了 add 函数,并将结果存储在 result 变量中,然后打印出结果。

你可以尝试更改函数的参数和返回值,看看它们是如何影响程序的。例如,你可以尝试创建一个返回两个数差的函数,或者返回两个数乘积的函数。

2、编写一个递归函数,如计算阶乘。

在这个练习中,你将使用递归函数来计算阶乘。阶乘是一个常见的递归例子,因为一个数的阶乘可以定义为它与其减1的数的阶乘的乘积,这就创造了递归的可能性。

下面是一个计算阶乘的函数的例子:

#include <stdio.h>

// 定义阶乘函数
long long factorial(int n) {
    if(n == 0) { // 基本情况
        return 1;
    } else {    // 递归情况
        return n * factorial(n - 1);
    }
}

int main() {
    int num = 5;
    long long result = factorial(num);

    printf("%d的阶乘是%lld\n", num, result);

    return 0;
}

在这个程序中,我们定义了一个计算阶乘的函数 factorial。这个函数有一个基本情况(当n为0时,返回1)和一个递归情况(返回n乘以n-1的阶乘)。

然后,在main函数中,我们调用了这个函数,传入了一个数字5,并将结果打印出来。

你可以试着改变 main 函数中的 num 变量的值,看看结果是如何变化的。你也可以试着编写其他递归函数,例如用于计算斐波那契数列的函数。

七、数组

(一)、基础概念

在C语言中,数组是由相同类型的元素组成的数据结构,这些元素在内存中连续存储。数组中的每个元素都可以通过数组名加索引来访问。

数组的声明

以下是C语言中数组声明的一般形式:

type arrayName [ arraySize ];

在这里,type 是数组中元素的数据类型,arrayName 是数组的名称,arraySize 指定了数组中元素的数量。

例如:

int myArray[10];

这段代码声明了一个包含10个整数的数组myArray

数组的初始化

当你声明一个数组,你可以同时进行初始化:

int myArray[5] = {1, 2, 3, 4, 5};

如果你省略掉数组的大小,编译器会自动计算:

int myArray[] = {1, 2, 3, 4, 5}; // 编译器会自动计算数组的大小

访问数组元素

数组中的元素是通过索引访问的,数组的索引从0开始,所以第一个元素的索引是0,第二个元素的索引是1,依此类推。

例如:

int myArray[5] = {1, 2, 3, 4, 5};
int first = myArray[0]; // 访问第一个元素
int second = myArray[1]; // 访问第二个元素

以上就是C语言中关于数组的基本信息。如果你有任何问题,或者想要讨论其他的部分,欢迎随时告诉我。

(二)、巩固练习

1、创建一个整型数组,填充并打印其内容。

在这个练习中,你将创建一个整数数组,填充它并打印其内容。以下是一个示例:

#include <stdio.h>

int main() {
    int numbers[5] = {1, 2, 3, 4, 5};
    int i;

    // 使用for循环打印数组内容
    for(i = 0; i < 5; i++) {
        printf("%d\n", numbers[i]);
    }

    return 0;
}

在这个程序中,我们首先创建了一个包含5个整数的数组 numbers,并初始化为1到5。然后我们使用 for 循环遍历数组并打印每个元素的值。

注意C中数组的索引从0开始,因此 numbers[0] 是数组的第一个元素, numbers[4] 是数组的最后一个元素。

你可以尝试更改数组的大小,更改初始化的值,或者更改打印元素的顺序,看看它们是如何影响程序的。例如,你可以尝试创建一个有10个元素的数组,或者将元素初始化为2的倍数,或者倒序打印元素。

2、尝试创建一个二维数组并打印其内容。

在这个练习中,你将创建一个二维数组,填充它并打印其内容。以下是一个示例:

#include <stdio.h>

int main() {
    int numbers[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
    int i, j;

    // 使用嵌套的for循环打印二维数组的内容
    for(i = 0; i < 3; i++) {
        for(j = 0; j < 3; j++) {
            printf("%d ", numbers[i][j]);
        }
        printf("\n");
    }

    return 0;
}

在这个程序中,我们首先创建了一个3x3的二维整数数组 numbers,并初始化为1到9。然后我们使用嵌套的 for 循环遍历二维数组并打印每个元素的值。

在C中,二维数组可以被视为一个表格,第一个索引表示行,第二个索引表示列。因此 numbers[0][0] 是数组的第一个元素, numbers[2][2] 是数组的最后一个元素。

你可以尝试更改数组的大小,更改初始化的值,或者更改打印元素的顺序,看看它们是如何影响程序的。例如,你可以尝试创建一个4x4的数组,或者将元素初始化为不同的值,或者倒序打印元素。

八、指针

(一)、基础概念

在C语言中,指针是一个非常重要的概念。一个指针变量指的是一个变量,其值为另一个变量的地址。换句话说,它“指向”了内存中的另一个位置。

声明指针

在C中,我们使用星号(*)来声明指针。以下是声明指针的一般格式:

type *var_name;

在这里,type 是指针的数据类型,var_name 是指针变量的名称。例如:

int *p;    // 声明一个整型指针 p
char *ch;  // 声明一个字符型指针 ch

初始化指针

指针可以在声明时被初始化。例如:

int var = 20;
int *p = &var;

在这个例子中,&var 是变量 var 的地址,所以 p 现在指向了 var

访问指针指向的值

当我们声明了一个指针并给它赋值后,我们可以通过解引用来访问它指向的值。解引用是通过在指针前面使用星号(*)来实现的。

例如:

int var = 20;   // 声明一个整型变量 var
int *p = &var;  // 声明并初始化一个指针 p
printf("%d", *p); // 输出 p 指向的值

这个代码将输出 20,也就是 p 指向的值。

以上就是C语言中关于指针的基本信息。如果你有任何问题,或者想要讨论其他的部分,欢迎随时告诉我。

(二)、巩固练习

1、创建一个指针,使其指向一个变量,并试图通过指针修改变量的值。

在这个练习中,你将创建一个指针,使其指向一个变量,并试图通过指针修改变量的值。以下是一个示例:

#include <stdio.h>

int main() {
    int number = 10;
    int *p;

    // 将指针p指向变量number
    p = &number;
    
    printf("原始值: %d\n", number);

    // 通过指针p修改number的值
    *p = 20;
    
    printf("修改后的值: %d\n", number);

    return 0;
}

在这个程序中,我们首先创建了一个整数变量 number 并初始化为10,然后我们创建了一个整数指针 p,并使它指向 number 的地址(通过 & 运算符)。然后我们打印 number 的原始值,通过指针 p 修改 number 的值,再打印 number 的新值。

注意,* 运算符被用来访问或修改指针所指向的值。所以 *p = 20; 的意思是 “将 p 所指向的变量的值设置为20”。

你可以尝试更改变量的初始值,或者通过指针修改为不同的值,看看它们是如何影响程序的。例如,你可以尝试将 number 初始化为其他值,或者通过指针将其修改为其他值。

2、尝试动态分配内存,如使用malloc函数。

在这个练习中,你将学习如何使用 malloc 函数动态分配内存。以下是一个示例:

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

int main() {
    int *ptr;
    int num = 5;

    // 使用malloc动态分配内存
    ptr = (int*)malloc(num * sizeof(int));

    if (ptr == NULL) {
        printf("内存分配失败。\n");
        return 1;
    }

    for (int i = 0; i < num; i++) {
        ptr[i] = i;
    }

    // 打印动态分配内存空间中的值
    for (int i = 0; i < num; i++) {
        printf("%d ", ptr[i]);
    }

    // 记得在使用完后释放内存
    free(ptr);

    return 0;
}

在这个程序中:

  • 我们首先定义了一个整型指针 ptr 和一个整型变量 num,并将 num 初始化为5。
  • 然后我们使用 malloc 函数为 numint 类型的变量分配了内存,sizeof(int) 用来获取 int 类型的大小。
  • 接着我们检查是否成功分配了内存。如果 ptrNULL,则表示内存分配失败。
  • 接着,我们使用循环将新分配的内存空间中的每个 int 初始化为它的索引值(也就是i)。
  • 然后,我们使用循环打印新分配的内存空间中的每个 int
  • 最后,我们使用 free 函数释放之前分配的内存,这是一个非常重要的步骤,如果忘记释放内存,会导致内存泄露,长期累积可能会使系统资源耗尽。

你可以尝试改变 num 的值,看看程序是如何为更多或更少的 int 分配内存的。你也可以尝试更改初始化的值,或者在释放内存之前尝试访问已分配的内存,看看会发生什么。

九、结构体

(一)、基础概念

在C语言中,结构体是一种用户定义的数据类型,允许你存储不同类型的数据项。它用于把一组逻辑相关的变量组织在一起。

定义结构体

定义结构体的一般格式如下:

struct structure_name {
   member_type1 member_name1;
   member_type2 member_name2;
   member_type3 member_name3;
   ...
};

例如,我们可以定义一个名为 Student 的结构体来存储学生的信息:

struct Student {
   char  name[50];
   int   roll;
   float marks;
};

在这个结构体中,namerollmarks 是结构体的成员。

创建结构体变量

定义了结构体类型后,我们就可以创建该类型的变量:

struct Student stu;

在这里,stuStudent 结构体的一个实例。

访问结构体成员

我们可以使用点运算符 . 来访问结构体的成员:

strcpy(stu.name, "Tom");
stu.roll = 123;
stu.marks = 89.5;

以上的代码将 “Tom” 赋给了 stuname 成员,123 赋给了 roll 成员,89.5 赋给了 marks 成员。

以上就是C语言中关于结构体的基本信息。如果你有任何问题,或者想要讨论其他的部分,欢迎随时告诉我。

(二)、巩固练习

1、创建一个结构体,如"学生",包含几个成员如姓名、年龄、分数,并创建该结构体的一个实例。

在这个练习中,你将创建一个名为 “学生” 的结构体,并添加一些成员变量,如姓名、年龄和分数。然后你将创建这个结构体的一个实例。以下是一个示例:

#include <stdio.h>

// 定义结构体
struct Student {
    char name[50];
    int age;
    int score;
};

int main() {
    // 创建结构体实例并初始化
    struct Student student1 = {"张三", 20, 85};

    printf("姓名:%s\n", student1.name);
    printf("年龄:%d\n", student1.age);
    printf("分数:%d\n", student1.score);

    return 0;
}

在这个程序中,我们首先定义了一个名为 “Student” 的结构体,它包含了一个字符数组(用于存储名字)、一个整数(用于存储年龄)和另一个整数(用于存储分数)。然后,我们在 main 函数中创建了这个结构体的一个实例 student1,并进行了初始化。

注意,结构体成员可以通过.运算符来访问。所以 student1.namestudent1.agestudent1.score 分别表示学生的名字、年龄和分数。

你可以试着添加更多的成员到结构体中,或者创建更多的结构体实例,看看它们是如何工作的。例如,你可以添加一个 “性别” 成员到结构体中,或者创建一个 “student2” 实例。

十、标准库函数

(一)、基础概念

C语言提供了大量的标准库函数,这些函数可以进行各种操作,如输入/输出处理、数学计算、字符处理、时间/日期处理等。这些函数被定义在不同的头文件中,你可以在需要使用这些函数的时候包含相应的头文件。

以下是一些常见的C语言标准库函数和它们所在的头文件:

  1. 输入/输出函数(stdio.h):包含了用于文件输入和输出的函数,如printf(), scanf(), fopen(), fclose()等。
  2. 数学函数(math.h):包含了数学计算的函数,如sqrt(), pow(), sin(), cos(), log()等。
  3. 字符和字符串处理函数(string.h / ctype.h)string.h包含了字符串处理的函数,如strcpy(), strcat(), strlen(), strcmp()等。ctype.h包含了字符处理的函数,如isalpha(), isdigit(), islower(), isupper(), tolower(), toupper()等。
  4. 时间日期函数(time.h):包含了处理日期和时间的函数,如time(), ctime(), strftime()等。

以上只是一小部分C语言的标准库函数,实际上,C语言的标准库函数非常丰富,可以满足绝大部分的编程需求。

以下是使用标准库函数的一个例子,我们使用 math.h 中的 sqrt() 函数来计算一个数的平方根:

#include <stdio.h>
#include <math.h>

int main() {
   double num = 9.0;
   double squareRoot = sqrt(num);

   printf("The square root of %.2f is %.2f\n", num, squareRoot);

   return 0;
}

以上就是C语言中关于标准库函数的基本信息。如果你有任何问题,或者想要讨论其他的部分,欢迎随时告诉我。

(二)、巩固练习

1、编写一个程序,使用math.h中的函数,如pow和sqrt。

在这个练习中,你将学习如何使用 math.h 库中的函数。以下是一个示例,使用了 pow(幂运算)和 sqrt(开方)函数:

#include <stdio.h>
#include <math.h>

int main() {
    double base = 2.0;
    double exponent = 3.0;
    double result;

    // 使用pow函数
    result = pow(base, exponent);
    printf("%lf的%lf次方等于:%lf\n", base, exponent, result);

    // 使用sqrt函数
    result = sqrt(result);
    printf("上面结果的平方根等于:%lf\n", result);

    return 0;
}

在这个程序中,我们首先定义了两个双精度浮点变量 baseexponent,并分别初始化为2.0和3.0。然后我们使用 pow 函数计算 baseexponent 次方,并将结果存储在 result 中。然后我们打印 result 的值。接着,我们使用 sqrt 函数计算 result 的平方根,并再次打印 result 的值。

注意,pow 函数的第一个参数是基数,第二个参数是指数。sqrt 函数只有一个参数,即要计算平方根的数。这两个函数都返回一个 double 类型的结果。

你可以尝试改变 baseexponent 的值,看看它们是如何影响结果的。你也可以尝试使用 math.h 中的其他函数,例如 sincostan 等。

2、使用string.h中的函数,如strcpy和strcmp。

在这个练习中,你将学习如何使用 string.h 库中的函数。以下是一个示例,使用了 strcpy(复制字符串)和 strcmp(比较字符串)函数:

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

int main() {
    char str1[20] = "Hello";
    char str2[20] = "World";
    char str3[20];

    // 使用strcpy函数复制字符串
    strcpy(str3, str1);
    printf("复制后的字符串是:%s\n", str3);

    // 使用strcmp函数比较字符串
    if(strcmp(str1, str2) == 0) {
        printf("字符串str1和str2是相同的。\n");
    } else {
        printf("字符串str1和str2是不同的。\n");
    }

    return 0;
}

在这个程序中,我们首先定义了三个字符数组 str1str2str3,并初始化 str1str2。然后我们使用 strcpy 函数将 str1 的内容复制到 str3,并打印 str3 的内容。接着,我们使用 strcmp 函数比较 str1str2 的内容。如果 strcmp 返回0,那么 str1str2 是相同的,否则它们是不同的。

注意,strcpy 函数的第一个参数是目标字符串,第二个参数是源字符串。strcmp 函数的两个参数是要比较的两个字符串。

你可以尝试更改 str1str2 的值,看看它们是如何影响结果的。你也可以尝试使用 string.h 中的其他函数,例如 strcat(连接字符串)、strlen(获取字符串长度)等。

十一、内存管理

(一)、基础概念

在C语言中,内存管理是一个重要的主题。你可以动态地在运行时分配和释放内存。C提供了几个函数,用于动态内存管理,这些函数在标准库stdlib.h中定义。

以下是C语言中的四个主要的内存管理函数:

  1. malloc()malloc函数在堆上动态地分配一定数量的连续内存。函数的原型如下:
void* malloc(size_t size);

malloc接受一个参数,这个参数是你希望分配的内存的字节数,然后返回一个指向新分配内存的指针,或者在无法分配内存时返回NULL。

  1. calloc()calloc函数在堆上动态地分配一定数量的连续内存,并将其初始化为0。函数的原型如下:
void* calloc(size_t num, size_t size);

calloc接受两个参数,第一个参数是你希望分配的元素的数量,第二个参数是每个元素的大小。calloc返回一个指向新分配内存的指针,或者在无法分配内存时返回NULL。

  1. realloc()realloc函数更改已分配内存区域的大小。函数的原型如下:
void* realloc(void* ptr, size_t size);

realloc接受两个参数,一个是先前由malloccallocrealloc分配的内存区域的指针,另一个是新的大小。realloc返回一个指向新分配内存的指针,或者在无法分配内存时返回NULL。

  1. free()free函数释放先前由malloccallocrealloc分配的内存区域。函数的原型如下:
void free(void* ptr);

free接受一个参数,这个参数是先前由malloccallocrealloc分配的内存区域的指针。

以下是一个使用mallocfree的示例:

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

int main() {
   int* ptr = malloc(sizeof(int));  // 分配内存

   if (ptr == NULL) {  // 检查是否成功分配内存
      printf("Memory allocation failed\n");
      return -1;
   }

   *ptr = 10;  // 在分配的内存上赋值
   printf("Value: %d\n", *ptr);

   free(ptr);  // 释放内存

   return 0;
}

以上就是C语言中关于内存管理的基本信息。如果你有任何问题,或者想要讨论其他的部分,欢迎随时告诉我。

(二)、巩固练习

1、使用malloc或calloc函数分配一些内存,然后使用free函数释放它。

在这个练习中,你将学习如何使用 malloccalloc 函数分配内存,以及如何使用 free 函数释放内存。以下是一个示例:

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

int main() {
    int *ptr1, *ptr2;
    int n = 5;

    // 使用malloc分配内存
    ptr1 = (int*)malloc(n * sizeof(int));
    if (ptr1 == NULL) {
        printf("内存分配失败。\n");
        return 1;
    }
    printf("使用malloc分配的内存地址:%p\n", ptr1);

    // 使用calloc分配内存
    ptr2 = (int*)calloc(n, sizeof(int));
    if (ptr2 == NULL) {
        printf("内存分配失败。\n");
        return 1;
    }
    printf("使用calloc分配的内存地址:%p\n", ptr2);

    // 释放分配的内存
    free(ptr1);
    free(ptr2);

    return 0;
}

在这个程序中,我们首先定义了两个整型指针 ptr1ptr2,以及一个整型变量 n,并将 n 初始化为5。然后我们使用 malloc 函数为 nint 类型的变量分配了内存,sizeof(int) 用来获取 int 类型的大小。接着我们检查是否成功分配了内存。如果 ptr1NULL,则表示内存分配失败。然后,我们使用 calloc 函数也为 nint 类型的变量分配了内存,并进行了同样的检查。最后,我们使用 free 函数释放了之前分配的内存。

注意,malloccalloc 的主要区别在于,malloc 分配的内存中的初始值是未定义的,而 calloc 分配的内存中的初始值都设置为0。

你可以尝试改变 n 的值,看看程序是如何为更多或更少的 int 分配内存的。你也可以尝试不释放内存,看看会发生什么(在实际编程中,忘记释放内存会导致内存泄漏,这是需要避免的)。

十二、综合习题

(一)、基础习题

当然,这是一道结合了以上知识点的综合题:

请编写一个程序,创建一个学生的结构体数组,结构体中包括学生的名字、年龄和分数。然后创建一个函数,接收这个结构体数组和数组的大小作为参数,函数内部为这个数组动态分配内存并对每个学生的信息进行初始化。最后在主函数中调用这个函数,并打印出每个学生的信息。最后,记得释放分配的内存。

以下是一个大概的程序结构:

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

// 学生结构体
struct Student {
    char name[50];
    int age;
    int score;
};

// 初始化函数
void initialize(struct Student* students, int size) {
    // TODO: 在这里填写代码,使用malloc或calloc为students分配内存,并初始化学生信息
}

// 打印学生信息函数
void print_students(struct Student* students, int size) {
    // TODO: 在这里填写代码,打印每个学生的信息
}

int main() {
    int size = 3; // 可以改变学生数量
    struct Student* students;

    initialize(students, size);
    print_students(students, size);

    // TODO: 在这里填写代码,释放分配的内存
    return 0;
}

这是一个比较复杂的程序,涉及到的知识点有:结构体、动态内存分配、函数和数组。你可以按照程序的要求,填写缺失的代码部分。当你编写代码的时候,不要忘记检查动态内存分配是否成功(即检查返回的指针是否为NULL),并在程序结束时释放分配的内存。

(二)进阶习题

1、题目

当然,这里有一个更具有挑战性且具有实际意义的问题。

假设你正在为一家图书馆编写一个图书管理系统。以下是你需要实现的功能:

  1. 定义一个"图书"的结构体,每本图书包含属性:书名、作者、出版年份和是否被借出(用一个整型变量表示,0代表没有被借出,1代表已被借出)。
  2. 创建一个函数,能够向图书馆的藏书中添加新的图书。每次添加新的图书时,需要动态分配内存来保存新的图书信息。
  3. 创建一个函数,能够根据书名查找图书。如果找到了这本书,就打印出这本书的所有信息。
  4. 创建一个函数,能够借出图书。该函数接收一个书名作为参数,如果这本书在库存中且没有被借出,就将其标记为已被借出。
  5. 在主函数中,提供一个菜单给用户,用户可以选择添加图书、查找图书或借出图书。
  6. 在退出程序前,记得释放所有动态分配的内存。

注意:这个问题需要你使用到结构体、动态内存分配(malloc或calloc)、函数、数组和控制流语句。你可能还需要使用到一些字符串处理函数,比如strcpy和strcmp,以处理和比较书名。

当你设计这个程序时,需要确保所有的用户输入都被正确处理,包括对图书数量的限制和对错误输入的处理。这个问题的挑战在于它需要你整合多个知识点,并设计出一个实际可用的系统。

2、示例答案

以下是我根据上述问题需求编写的一个简单的图书管理系统。这个程序使用了一个结构体数组来存储图书,使用了malloc来动态分配内存,同时使用了几个函数来执行不同的任务:

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

#define MAX_BOOK_NAME 50
#define MAX_AUTHOR_NAME 50

// 图书结构体
typedef struct {
    char bookName[MAX_BOOK_NAME];
    char authorName[MAX_AUTHOR_NAME];
    int publicationYear;
    int isBorrowed;
} Book;

// 图书数组和图书数量
Book* library = NULL;
int bookCount = 0;

// 添加图书
void addBook(char* bookName, char* authorName, int publicationYear) {
    library = (Book*)realloc(library, (bookCount + 1) * sizeof(Book));
    strcpy(library[bookCount].bookName, bookName);
    strcpy(library[bookCount].authorName, authorName);
    library[bookCount].publicationYear = publicationYear;
    library[bookCount].isBorrowed = 0;
    bookCount++;
}

// 查找图书
void findBook(char* bookName) {
    for (int i = 0; i < bookCount; i++) {
        if (strcmp(library[i].bookName, bookName) == 0) {
            printf("书名:%s\n", library[i].bookName);
            printf("作者:%s\n", library[i].authorName);
            printf("出版年份:%d\n", library[i].publicationYear);
            printf("是否借出:%s\n", library[i].isBorrowed ? "是" : "否");
            return;
        }
    }
    printf("找不到名为%s的图书。\n", bookName);
}

// 借出图书
void borrowBook(char* bookName) {
    for (int i = 0; i < bookCount; i++) {
        if (strcmp(library[i].bookName, bookName) == 0) {
            if (!library[i].isBorrowed) {
                library[i].isBorrowed = 1;
                printf("图书%s已借出。\n", bookName);
            } else {
                printf("图书%s已被借出。\n", bookName);
            }
            return;
        }
    }
    printf("找不到名为%s的图书。\n", bookName);
}

// 主函数
int main() {
    addBook("书名1", "作者1", 2000);
    addBook("书名2", "作者2", 2005);
    addBook("书名3", "作者3", 2010);

    findBook("书名1");
    findBook("书名4");

    borrowBook("书名2");
    borrowBook("书名2");
    borrowBook("书名4");

    free(library); // 不要忘记释放动态分配的内存

    return 0;
}

注意:这只是一个基础的图书管理系统,它没有提供用户界面,所有的操作都是在代码中直接调用的。如果你想让这个程序更实用,你可以添加一个用户界面,让用户可以在运行时添加、查找和借出图书。你还可以添加更多的功能,比如删除图书、返回图书,等等。

3、答案详解

当然可以,我将一步一步地解释这个程序。

  1. 首先,我们定义了一个叫做Book的结构体,其中包含了书名、作者名、出版年份以及是否已经被借出的信息。
typedef struct {
    char bookName[MAX_BOOK_NAME];
    char authorName[MAX_AUTHOR_NAME];
    int publicationYear;
    int isBorrowed;
} Book;
  1. 然后我们定义了一个指向Book类型的指针library和一个表示图书数量的变量bookCountlibrary将作为一个动态数组,用于存储所有的图书信息。
Book* library = NULL;
int bookCount = 0;
  1. addBook函数用于添加新的图书到图书库。首先,我们通过realloc函数扩展library数组的大小,然后将新图书的信息复制到新的位置,最后增加图书数量。
void addBook(char* bookName, char* authorName, int publicationYear) {
    library = (Book*)realloc(library, (bookCount + 1) * sizeof(Book));
    strcpy(library[bookCount].bookName, bookName);
    strcpy(library[bookCount].authorName, authorName);
    library[bookCount].publicationYear = publicationYear;
    library[bookCount].isBorrowed = 0;
    bookCount++;
}
  1. findBook函数用于查找图书。它会遍历library数组,如果找到了匹配的图书,就会打印出图书的信息。
void findBook(char* bookName) {
    for (int i = 0; i < bookCount; i++) {
        if (strcmp(library[i].bookName, bookName) == 0) {
            printf("书名:%s\n", library[i].bookName);
            printf("作者:%s\n", library[i].authorName);
            printf("出版年份:%d\n", library[i].publicationYear);
            printf("是否借出:%s\n", library[i].isBorrowed ? "是" : "否");
            return;
        }
    }
    printf("找不到名为%s的图书。\n", bookName);
}
  1. borrowBook函数用于借阅图书。同样,它会遍历library数组,如果找到了匹配的图书并且图书没有被借出,就将其标记为已借出。
void borrowBook(char* bookName) {
    for (int i = 0; i < bookCount; i++) {
        if (strcmp(library[i].bookName, bookName) == 0) {
            if (!library[i].isBorrowed) {
                library[i].isBorrowed = 1;
                printf("图书%s已借出。\n", bookName);
            } else {
                printf("图书%s已被借出。\n", bookName);
            }
            return;
        }
    }
    printf("找不到名为%s的图书。\n", bookName);
}
  1. main函数中,我们添加了一些图书,并进行了查找和借阅的操作。
int main() {
    addBook("书名1", "作者1", 2000);
    addBook("书名2", "作者2", 2005);
    addBook("书名3", "作者3", 2010);

    findBook("书名1");
    findBook("书名4");

    borrowBook("书名2");
    borrowBook("书名2");
    borrowBook("书名4");

    free(library); // 不要忘记释放动态分配的内存

    return 0;
}
  1. 在程序结束时,我们用free函数释放了通过malloc分配的内存,以防止内存泄漏。
free(library); // 不要忘记释放动态分配的内存

整个程序都基于这些函数来完成对图书的添加、查找和借阅操作,通过动态内存分配,能够根据需要来扩展图书的存储空间。这是一个简单的命令行界面的图书管理系统,如果你想让它变得更复杂和实用,你可以添加更多的功能和改进用户界面。

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值