【408直通车】一站式备考:408考试C语言全面总复习

发布时间:2024年01月19日

前言

高效的备考是取得优异成绩的关键。本文旨在为初学者提供全面而系统的指南,帮助他们逐步掌握C语言、数据结构与算法、低级编程以及汇编语言等关键概念。通过本文的学习,读者将建立坚实的计算机基础,为深入学习计算机科学奠定坚实基础。

文章目录

1. 导论与环境搭建

1.1 课程导学,编程环境搭建

1.1.1 C语言简介

C语言是由Dennis Ritchie于1972年开发的一种通用性编程语言。其高效性和底层控制能力使其在系统编程和嵌入式系统领域得到广泛应用。在这一小节,我们将简要介绍C语言的历史、应用领域,并为学习者提供学习C语言的动机和意义。

1.1.2 为什么学习C语言?
  • C语言是计算机科学基础,有助于理解底层原理。
  • 在系统编程和嵌入式系统领域,C语言是主流开发语言。
  • 学习C语言有助于提高对计算机内部工作原理的理解。
1.1.3 编程环境搭建

学习C语言的第一步是搭建编程环境。以下是步骤:

  1. 下载编译器: 选择一个C语言编译器,如GCC(GNU Compiler Collection),并下载安装。
  2. 选择集成开发环境(IDE): 选择一个IDE,如Code::Blocks或Dev-C++,并安装。
  3. 验证环境: 编写一个简单的Hello World程序,并运行,确保编程环境配置正确。

链接:Dev-C++

1.1.3.1 Hello World程序示例
#include <stdio.h>

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

以上是一个简单的Hello World程序,用于验证C语言编程环境是否配置正确。

这是第一章的导论部分,介绍了C语言的背景和搭建编程环境的步骤。在确保你的编程环境正常运行后,我们将进入下一章,深入学习C语言的基础语法。

2. 基础语法

2.1 数据的类型、数据的输入输出

2.1.1 数据的类型

C语言支持多种数据类型,包括整型(4)、浮点型(4)、字符型(1)等。

2.1.1.1 整型
#include <stdio.h>

int main() {
    int integerVar = 10;
    printf("Integer Variable: %d\n", integerVar);

    return 0;
}
#include <stdio.h>

// 自定义函数,输出二进制数的原样表示
void printBinary(int num) {
    if (num > 1) {
        printBinary(num / 2);
    }
    printf("%d", num % 2);
}

int main() {
    // 二进制表示
    int binaryNumber = 123456789; // 十进制数
    printf("二进制表示:");
    printBinary(binaryNumber);
    printf(", 十进制表示:%d\n", binaryNumber);

    // 八进制表示
    int octalNumber = 0726746425; // 八进制数
    printf("八进制表示:%o, 十进制表示:%d\n", octalNumber, octalNumber);

    // 十六进制表示
    int hexadecimalNumber = 0x75BCD15; // 十六进制数
    printf("十六进制表示:%x, 十进制表示:%d\n", hexadecimalNumber, hexadecimalNumber);

    // 十进制表示
    int decimalNumber = 123456789;
    printf("十进制表示:%d\n", decimalNumber);

    // 内存中的表示
    int i = 1234567899;
    printf("整数 1234567899 在内存中的表示:%p\n", (void*)&i);

    return 0;
}

2.1.1.2 浮点型
#include <stdio.h>

int main() {
    float floatVar = 3.14;
    printf("Float Variable: %f\n", floatVar);
    // 正确示例
    printf("1e3: %f\n", 1e3);    // 输出:1000.000000
    printf("1.8e-3: %f\n", 1.8e-3); // 输出:0.001800
    printf("-123e-6: %f\n", -123e-6); // 输出:-0.000123
    printf("-.1e-3: %f\n", -.1e-3);  // 输出:-0.000100

    // 错误示例
    // 下面的代码在编译时会导致错误
    // printf("e3: %f\n", e3);     // 错误,e前面没有数字
    // printf("2.1e3.5: %f\n", 2.1e3.5); // 错误,指数部分必须是整数
    // printf(".e3: %f\n", .e3);    // 错误,e前面没有数字
    // printf("e.: %f\n", e.);      // 错误,e后面没有指数
    return 0;
}


以上代码演示了浮点型变量的声明和输出。

2.1.1.3 字符型
#include <stdio.h>

int main() {
    char charVar = 'A';
    printf("Character Variable: %c\n", charVar);

    return 0;
}

以上代码演示了字符型变量的声明和输出。

2.1.2 数据的输入输出
2.1.2.1 输入

数据输入是程序接收外部信息的过程。在C语言中,常用的输入函数有:

  1. scanf
    • 用于从标准输入(通常是键盘)获取数据。
    • 示例:
      int num;
      scanf("%d", &num);
      

当我们处理C语言中的输入输出时,使用标准函数库中的scanf函数可以从标准输入(通常是键盘)读取数据。下面详细解释了scanf函数的原理以及多种数据类型混合输入的情况。

  1. fgets

    • 用于从文件流或标准输入获取一行字符串。
    • 示例:
      char buffer[50];
      fgets(buffer, sizeof(buffer), stdin);
      
  2. getchar

    • 用于从标准输入获取单个字符。
    • 示例:
      char ch;
      ch = getchar();
      
1. scanf 函数的原理

C语言的输入输出是通过标准函数库来实现的,而scanf函数用于读取键盘输入,即标准输入。以下是scanf函数的一些原理:

  • scanf函数在读取标准输入时,如果还没有输入任何内容,会被阻塞(阻塞是指等待输入)。
  • 使用格式控制字符串指定要读取的数据类型,如 %d 表示整数,%f 表示浮点数,%c 表示字符。对于整数和浮点数,需要使用 & 取地址。
  • 如果在输入中存在空格或换行符(\n),scanf会忽略它们,除非在格式控制字符串中显式使用。

例子:

在你提供的代码中,你演示了使用scanf函数读取整数和字符,并对空格和换行符的处理进行了详细说明。下面对代码进行解释:

#include <stdio.h>

int main() {
    int i = 10;
    char a, b, c;

    // 读取整数
    scanf("%d", &i);
    printf("%d\n", i);

    // 读取字符,注意这里可能会有问题
    scanf("%c", &a);
    printf("a=%c\n", a);

    fflush(stdin); // 清空标准输入缓冲区

    // 读取字符,注意在%c前加空格
    scanf(" %c", &b);
    printf("b=%c\n", b);

    // 读取字符,同样在%c前加空格
    scanf(" %c", &c);
    printf("c=%c\n", c);

    return 0;
}

解释:

  1. 通过scanf("%d", &i);读取整数,并打印输出。

  2. 通过scanf("%c", &a);读取字符,但这里可能会出现问题。在执行这一行时,如果前面有回车符或空格等空白字符在输入缓冲区中,scanf("%c", &a);会读取这些空白字符,而不会等待用户输入字符。为了解决这个问题,可以在这一行之前加入一个空格,即scanf(" %c", &a);

  3. 使用fflush(stdin);清空标准输入缓冲区,以确保下一个scanf函数不受之前输入的影响。

  4. 通过scanf(" %c", &b);读取字符,并打印输出。这里加入了空格,以确保忽略掉可能存在的空白字符。

  5. 同样通过scanf(" %c", &c);读取字符,并打印输出。同样加入了空格来处理可能的空白字符。

需要注意的是,fflush(stdin);在标准C中是未定义的行为,因此在不同的编译器和平台上可能会有不同的效果。为了更好的可移植性,可以考虑使用其他方法来清空输入缓冲区。

2. 多种数据类型混合输入

当一次调用scanf函数读取多种数据类型时,特别需要注意字符型数据。在一行数据中存在字符型数据读取时,读取的字符不会忽略空格和换行符。

例子:

#include <stdio.h>

int main() {
    int i, ret;
    char c;
    float f;

    // 读取整数、字符、浮点数
    ret = scanf("%d %c%f", &i, &c, &f); // 在%c之前加个空格
    printf("i=%d,c=%c,f=%5.2f\n", i, c, f);

    return 0;
}

在上述例子中,scanf函数匹配成功了4个成员,返回值为4。通过返回值可以判断scanf函数匹配成功了几个成员。如果中间任何一个成员匹配出错,后面的成员都会匹配出错。

这些是关于scanf函数原理和多种数据类型混合输入的详细解释。

2.1.2.2 输出

数据输出是程序向外部传递信息的过程。在C语言中,常用的输出函数有:

  1. printf
    • 用于格式化输出数据。
    • 示例:
      char name[] = "John";
      int age = 25;
      printf("姓名:%s,年龄:%d\n", name, age);
      

printf 函数中,可以使用格式化控制符控制输出的对齐方式。右对齐是其中一种对齐方式,用于让输出的内容在字段宽度内右对齐显示。以下是一个简单的示例:

#include <stdio.h>

int main() {
    int number = 42;

    // 右对齐,字段宽度为 10
    printf("右对齐:%10d\n", number);

    return 0;
}

在这个例子中,%10d 中的 10 指定了字段宽度为10,而 %d 表示要输出的是一个整数。当整数的位数不足10位时,将在左侧填充空格,以实现右对齐。

输出结果:

右对齐:        42

注意,字段宽度的值可以根据实际需要进行调整。右对齐在某些输出格式的表格或报表中很有用,使得数字在列中对齐整齐。
2. puts

  • 输出字符串并自动换行。
  • 示例:
    char str[] = "Hello";
    puts(str);
    
  1. putchar

    • 输出单个字符。
    • 示例:
      char ch = 'A';
      putchar(ch);
      
  2. fprintf

    • 将格式化的数据输出到文件流。
    • 示例:
      FILE *file = fopen("output.txt", "w");
      fprintf(file, "This is a formatted output: %d", 42);
      fclose(file);
      
  3. sprintf

    • 将格式化的数据输出到字符串。
    • 示例:
      char buffer[50];
      sprintf(buffer, "This is a formatted output: %d", 42);
      

以上是一些常用的输入输出函数,程序员根据具体需求选择合适的函数以满足程序的输入和输出操作。在使用时需要注意数据的安全性和正确性。

2.1.3 #define
#include <stdio.h>

// 定义常量
#define PI 3.14159
#define MAX_VALUE 100
#define GREETING "你好,世界!"

// 定义欢迎消息宏
#define WELCOME_MESSAGE() printf("欢迎来到宏的世界!\n")

// 定义计算平方宏
#define SQUARE(x) ((x) * (x))

// 定义加法宏
#define ADD(a, b) ((a) + (b))

// 定义圆的面积计算宏
#define AREA_OF_CIRCLE(radius) (PI * SQUARE(radius))

// 定义调试开关
#define DEBUG 1

// 根据调试开关定义调试信息宏
#ifdef DEBUG
#define DEBUG_MESSAGE(message) printf("调试:%s\n", message)
#else
#define DEBUG_MESSAGE(message)
#endif

// 根据最大值判断消息内容宏
#if MAX_VALUE > 50
#define MESSAGE "最大值大于50"
#else
#define MESSAGE "最大值为50或更小"
#endif

// 定义特性开关
#define FEATURE_ENABLED

// 根据特性开关定义特性函数宏
#ifdef FEATURE_ENABLED
#define FEATURE_FUNCTION() printf("功能已启用。\n")
#else
#undef FEATURE_FUNCTION
#endif

// 定义连接宏
#define CONCAT(a, b) a ## b

// 定义字符串化宏
#define STRINGIFY(x) #x

// 定义求最大值宏
#define MAXIMUM(a, b) ((a) > (b) ? (a) : (b))

// 定义可变参数宏
#define PRINT_VARIABLES(...) printf(__VA_ARGS__)

// 定义记录日志信息宏
#define LOG_MESSAGE(message) printf("[%s:%d] %s\n", __FILE__, __LINE__, message)

// 定义常量值
#define CONSTANT_VALUE 42

// 定义不带括号的平方宏
#define SQUARE_NO_PAREN(x) ((x) * (x))

// 定义计算矩形面积宏
#define CALCULATE_AREA(length, width) ((length) * (width))

#define PO 3+2

// 主函数
int main() {
	// 打印欢迎消息
	WELCOME_MESSAGE();
	printf("原样输出:%d\n", PO * 2);

	// 计算并打印5的平方
	int side = 5;
	printf("5的平方是:%d\n", SQUARE(side));

	// 计算并打印3和4的和
	printf("3和4的和是:%d\n", ADD(3, 4));

	// 根据调试开关打印调试信息
	DEBUG_MESSAGE("调试中...");

	// 打印根据最大值判断的消息内容
	printf("消息:%s\n", MESSAGE);

	// 根据特性开关调用特性函数
	FEATURE_FUNCTION();

	// 打印连接后的值
	printf("连接后的值:%d\n", CONCAT(10, 20));

	// 打印字符串化后的值
	printf("字符串化后的值:%s\n", STRINGIFY(test));

	// 计算并打印8和12的最大值
	printf("8和12的最大值是:%d\n", MAXIMUM(8, 12));

	// 打印可变参数宏
	PRINT_VARIABLES("变量的值:%d, %f, %s\n", 42, 3.14, "你好");

	// 记录日志信息
	LOG_MESSAGE("记录这条消息");

	// 打印常量值
	printf("常量的值:%d\n", CONSTANT_VALUE);

	// 打印不带括号的平方
	printf("不带括号的平方:%d\n", SQUARE_NO_PAREN(5));

	// 计算并打印矩形的面积
	printf("矩形的面积:%d\n", CALCULATE_AREA(4, 8));

	// 返回0表示成功执行
	return 0;
}



2.2 运算符与表达式

2.2.1 什么是运算符?

运算符是一种用于执行操作的特殊符号,可以对一个以上的操作数进行运算。C语言支持多种运算符,包括算术运算符、关系运算符和逻辑运算符等。

2.2.2 常见运算符
  • 算术运算符: +(加法)、-(减法)、*(乘法)、/(除法)等。
  • 关系运算符: ==(等于)、!=(不等于)、>(大于)、<(小于)等。
  • 逻辑运算符: &&(逻辑与)、||(逻辑或)、!(逻辑非)等。
2.2.3 表达式

表达式是由操作数和运算符组成的序列,用于计算某个值。C语言中的表达式可以包括常量、变量、运算符等。

2.2.3.1 表达式示例

知识点总结:

  1. 算术运算符:

    • 示例代码:

      int result_arithmetic = 4 + 5 * 2 - 6 / 3 + 10 % 4;
      
  2. 关系运算符:

    • 示例代码:

      int a;
      while (scanf("%d", &a)) {
          if (a > 3 && a < 10) {
              printf("a 在 3 和 10 之间\n");
          } else {
              printf("a 不在 3 和 10 之间\n");
          }
      }
      
  3. 逻辑运算符:

    • 示例代码:

      int x = 1, y = 0;
      printf("AND 运算:%d\n", x && y);
      printf("OR 运算:%d\n", x || y);
      printf("NOT 运算:%d\n", !x);
      
  4. 位运算符:

    • 示例代码:

      int x = 5, y = 3;
      printf("按位与运算:%d\n", x & y);
      printf("按位或运算:%d\n", x | y);
      printf("按位异或运算:%d\n", x ^ y);
      printf("左移运算:%d\n", x << 1);
      printf("右移运算:%d\n", x >> 1);
      
  5. 赋值运算符:

    • 示例代码:

      int a = 5;
      a += 3;
      
  6. 条件运算符:

    • 示例代码:

      int x = 10, y = 20;
      int result = (x > y) ? x : y;
      
  7. 逗号运算符:

    • 示例代码:

      int a = 5, b = 10, c = 15;
      int result = (a++, b++, c++);
      
  8. 指针运算符:

    • 示例代码:

      int num = 42;
      int *ptr = &num;
      
  9. 求字节数运算符:

    • 示例代码:

      printf("int 类型字节数:%lu\n", sizeof(int));
      
  10. 强制类型转换运算符:

    • 示例代码:

      double x = 5.67;
      int y = (int)x;
      
  11. 分量运算符(结构体):

    • 示例代码:

      struct Point {
          int x;
          int y;
      };
      
      struct Point p;
      p.x = 3;
      p.y = 7;
      
  12. 下标运算符(数组):

    • 示例代码:

      int numbers[] = {1, 2, 3, 4, 5};
      printf("数组下标访问:%d\n", numbers[2]);
      
  13. 其他运算符(函数调用):

    • 示例代码:

      int add(int a, int b) {
          return a + b;
      }
      
      int result = add(3, 7);
      

以上是C语言中不同类型的运算符及其具体使用的示例代码。

2.3 选择、循环

2.3.1 选择结构

选择结构允许根据条件的真假执行不同的代码块。C语言提供了if语句和switch语句来实现选择结构。

2.3.1.1 if语句示例
#include <stdio.h>

int main() {
    int num = 10;

    if (num > 0) {
        printf("Number is positive.\n");
    } else if (num < 0) {
        printf("Number is negative.\n");
    } else {
        printf("Number is zero.\n");
    }

    return 0;
}

以上代码演示了使用if语句判断一个数的正负。

2.3.2 循环结构

循环结构允许多次执行相同的代码块,C语言提供了forwhiledo-while等循环语句。

2.3.2.1 for循环示例
#include <stdio.h>

int main() {
    for (int i = 1; i <= 5; i++) {
        printf("%d ", i);
    }

    return 0;
}

以上代码演示了使用for循环输出1到5的数字。

2.3.2.2 while循环示例
#include <stdio.h>

int main() {
    int i = 1;

    while (i <= 5) {
        printf("%d ", i);
        i++;
    }

    return 0;
}

以上代码演示了使用while循环实现相同的输出效果。

2.4 一维数组与字符数组

2.4.1 一维数组

一维数组是一组相同类型的元素的集合,每个元素都有一个唯一的索引。

2.4.1.1 一维数组示例
#include <stdio.h>

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

    for (int i = 0; i < 5; i++) {
        printf("%d ", numbers[i]);
    }

    return 0;
}

以上代码演示了如何声明、初始化并遍历一维数组。

2.4.2 字符数组

字符数组是一种特殊的一维数组,用于存储字符串。

2.4.2.1 字符数组示例
#include <stdio.h>
#include <string.h>

int main() {
	// 输入字符串
	char inputString[50];  // 假设字符串的最大长度是50
	printf("请输入字符串:");
	fgets(inputString, sizeof(inputString), stdin);

	// 输出字符串和长度
	printf("输入的字符串是:%s,长度为%d\n", inputString, strlen(inputString));

	// 计算字符串长度
	printf("Manual字符串长度(未添加 \\0):%zu\n", strlen("Manual"));

	char manualString[7] ;
	manualString[0] = 'M';
	manualString[1] = 'a';
	manualString[2] = 'n';
	manualString[3] = 'u';
	manualString[4] = 'a';
	manualString[5] = 'l';
	// 手动操作后的字符串
	printf("手动操作后的字符串(未添加 \\0):%s,长度:%zu\n", manualString, strlen(manualString));

	// 手动在字符串末尾添加 \0
	manualString[6] = '\0';

	// 手动操作后的字符串
	printf("手动操作后的字符串(添加了 \\0):%s,长度:%zu\n", manualString, strlen(manualString));

	return 0;
}

在这里插入图片描述
在分析你提供的运行结果时,发现一些问题,让我们逐一看:

  1. 输入字符串:

    请输入字符串:123
    

    用户输入了字符串 “123”。

  2. 输出字符串和长度:

    输入的字符串是:123
    ,长度为4
    

    这里输出的长度为4,但实际上用户输入的字符串 “123” 的长度应该是3。这是因为fgets函数在读取字符串时会包含换行符\n,导致字符串长度增加。

  3. 计算字符串长度:

    Manual字符串长度(未添加 \0):6
    

    这里计算的 “Manual” 字符串的长度为6,是正确的。

  4. 手动操作后的字符串(未添加 \0):

    手动操作后的字符串:Manual?23
    ,长度:11
    

    这里手动操作后的字符串显示为 “Manual?23”,长度为11。问题出在手动操作时未正确添加 \0,导致printf在输出字符串时会继续输出内存中的数据直到遇到 \0。在这里,看起来像是字符串 “123” 的部分被追加到了 “Manual” 后面。

  5. 手动操作后的字符串(添加了 \0):

    手动操作后的字符串:Manual,长度:6
    

    在手动添加了 \0 之后,字符串正确显示为 “Manual”,长度为6。

总结:主要问题出在用户输入字符串的长度计算上,以及手动操作时未正确添加 \0。正确的手动操作后的字符串应该是 “Manual” 而不是 “Manual?23”。在使用 fgets 读取用户输入时,可以考虑去掉末尾的换行符,以避免计算长度时出现偏差。

%d%u%zu

下面是一个包含 %d%u%zu 的具体C代码示例,使用了一些极端数据:

#include <stdio.h>

int main() {
    // 有符号整数(%d)
    int myInt = -2147483648;  // INT_MIN
    printf("有符号整数:%d\n", myInt);

    // 无符号整数(%u)
    unsigned int myUnsignedInt = 4294967295;  // UINT_MAX
    printf("无符号整数:%u\n", myUnsignedInt);

    // size_t 类型(%zu)
    size_t mySizeT = 18446744073709551615ull;  // SIZE_MAX
    printf("size_t 类型:%zu\n", mySizeT);

    return 0;
}

在这个例子中:

  • %d 用于有符号整数,我使用了 INT_MIN,即有符号整数的最小值。
  • %u 用于无符号整数,我使用了 UINT_MAX,即无符号整数的最大值。
  • %zu 用于 size_t 类型,我使用了 SIZE_MAX,即 size_t 的最大值。

这个示例演示了如何使用这三个格式说明符,以及它们分别适用的情况。需要注意,使用正确的格式说明符是很重要的,因为它影响了输出的正确性和避免了潜在的警告或错误。

2.5 指针

2.5.1 什么是指针?

指针是一个变量,其值为另一个变量的地址。C语言中,指针提供了直接访问和操作内存地址的能力。

2.5.2 指针的声明和初始化

要声明一个指针,需要指定指针变量的类型,然后使用*运算符表示这是一个指针。初始化指针时,可以将其指向一个变量的地址。

2.5.2.1 指针声明和初始化示例
#include <stdio.h>

int main() {
    int number = 42;
    int *pointer; // 壓明整型指针
    pointer = &number; // 将指针指向变量的地址

    printf("Value of number: %d\n", number);
    printf("Address of number: %p\n", &number);
    printf("Value of pointer: %p\n", pointer);

    return 0;
}

以上代码演示了如何声明、初始化指针,并访问变量的地址。

2.5.3 指针的应用

指针在C语言中有广泛的应用,包括传递函数参数、动态内存分配等。

2.5.3.1 指针作为函数参数示例
#include <stdio.h>

// 交换两个整数的值
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int num1 = 5, num2 = 10;

    printf("Before swapping: num1 = %d, num2 = %d\n", num1, num2);

    swap(&num1, &num2);

    printf("After swapping: num1 = %d, num2 = %d\n", num1, num2);

    return 0;
}

以上代码演示了如何使用指针作为函数参数,实现两个整数值的交换。

2.6 函数

2.6.1 什么是函数?

函数是一段可重用的代码,用于执行特定的任务。C语言中,函数包括函数头和函数体,可以有参数和返回值。

2.6.2 函数的声明和定义

在使用函数之前,需要先声明函数,然后在后面的代码中定义函数。

2.6.2.1 函数声明和定义示例
#include <stdio.h>

// 函数声明
int add(int a, int b);

int main() {
    int result = add(5, 3);
    printf("Result of addition: %d\n", result);

    return 0;
}

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

以上代码演示了如何声明并定义一个简单的加法函数。

2.6.3 递归函数

递归函数是调用自身的函数。在使用递归时,需要确保有终止条件,否则会导致无限递归。

2.6.3.1 递归函数示例
#include <stdio.h>

// 计算阶乘
int factorial(int n) {
    if (n <= 1) {
        return 1; // 终止条件
    } else {
        return n * factorial(n - 1); // 递归调用
    }
}

int main() {
    int num = 5;
    printf("Factorial of %d: %d\n", num, factorial(num));

    return 0;
}

以上代码演示了递归函数的应用,计算了一个数的阶乘。

2.7 结构体与C++引用讲解

2.7.1 结构体

结构体是一种用户自定义的数据类型,允许存储不同类型的数据。

2.7.1.1 结构体示例
#include <stdio.h>

// 定义结构体
struct Point {
    int x;
    int y;
};

int main() {
    // 声明结构体变量
    struct Point p1;
    
    // 初始化结构体成员
    p1.x = 10;
    p1.y = 20;

    printf("Point coordinates: (%d, %d)\n", p1.x, p1.y);

    return 0;
}

以上代码演示了如何定义和使用结构体。

2.7.2 C++引用

C++引用是一个变量的别名,通过引用可以更方便地操作变量。

2.7.2.1 C++引用示例
#include <iostream>

int main() {
    int num = 42;
    int &refNum = num; // 定义引用

    std::cout << "Value of num: " << num << std::endl;
    std::cout << "Value of refNum: " << refNum << std::endl;

    refNum = 55; // 修改引用

    std::cout << "After modifying refNum, value of num: " << num << std::endl;
    std::cout << "After modifying refNum, value of refNum: " << refNum << std::endl;

    return 0;
}

以上代码演示了如何定义C++引用,并通过引用操作变量。修改引用的值将影响原始变量的值。

2.8 C语言语法进阶

2.8.1 动态内存分配

动态内存分配允许在运行时分配内存空间,使用mallocfree函数。

2.8.1.1 动态内存分配示例
#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr;
    int size = 5;

    // 分配动态内存
    arr = (int *)malloc(size * sizeof(int));

    // 初始化动态数组
    for (int i = 0; i < size; i++) {
        arr[i] = i + 1;
    }

    // 打印数组元素
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }

    // 释放动态内存
    free(arr);

    return 0;
}

以上代码演示了如何使用动态内存分配创建动态数组,并在使用完毕后释放内存。

2.8.2 文件操作

C语言提供了文件操作函数,用于读写文件。常用的函数有fopenfclosefreadfwrite等。

2.8.2.1 文件操作示例
#include <stdio.h>

int main() {
    FILE *file;
    char content[] = "Hello, File Handling!";

    // 打开文件
    file = fopen("example.txt", "w");

    // 写入文件
    fwrite(content, sizeof(char), sizeof(content), file);

    // 关闭文件
    fclose(file);

    return 0;
}

以上代码演示了如何使用文件操作函数创建并写入文件。

3. 数据结构与算法

3.1 数据结构概述

3.1.1 什么是数据结构?

数据结构是一种组织和存储数据的方式,旨在高效地访问和修改数据。常见的数据结构包括数组、链表、栈、队列、树等。

3.1.2 数据结构的分类
  • 线性结构: 数据元素之间存在一对一的关系,如数组、链表、栈、队列。
  • 非线性结构: 数据元素之间存在一对多或多对多的关系,如树、图。

3.2 线性表代码实战

3.2.1 什么是线性表?

线性表是具有相同数据类型的n个数据元素的有限序列,其中n称为线性表的长度。

3.2.1.1 线性表代码实战示例
#include <stdio.h>

#define MAX_SIZE 10

struct LinearList {
    int elements[MAX_SIZE];
    int length;
};

void initializeList(struct LinearList *list) {
    list->length = 0;
}

void insertElement(struct LinearList *list, int element) {
    if (list->length < MAX_SIZE) {
        list->elements[list->length] = element;
        list->length++;
    } else {
        printf("Linear list is full. Cannot insert element.\n");
    }
}

void displayList(struct LinearList *list) {
    printf("Linear List: ");
    for (int i = 0; i < list->length; i++) {
        printf("%d ", list->elements[i]);
    }
    printf("\n");
}

int main() {
    struct LinearList myList;
    initializeList(&myList);

    insertElement(&myList, 10);
    insertElement(&myList, 20);
    insertElement(&myList, 30);

    displayList(&myList);

    return 0;
}

以上代码演示了线性表的实现,包括初始化、插入元素和显示线性表。

3.3 单链表的新建、查找、删除

3.3.1 什么是单链表?

单链表是一种数据元素按照链式存储的线性表,每个元素包含一个数据项和一个指向下一个元素的指针。

3.3.1.1 单链表新建、查找、删除示例
#include <stdio.h>
#include <stdlib.h>

struct Node {
    int data;
    struct Node *next;
};

struct LinkedList {
    struct Node *head;
};

void initializeList(struct LinkedList *list) {
    list->head = NULL;
}

void insertNode(struct LinkedList *list, int data) {
    struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = list->head;
    list->head = newNode;
}

void displayList(struct LinkedList *list) {
    struct Node *current = list->head;
    printf("Linked List: ");
    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

int searchNode(struct LinkedList *list, int target) {
    struct Node *current = list->head;
    int position = 1;

    while (current != NULL) {
        if (current->data == target) {
            return position;
        }
        current = current->next;
        position++;
    }

    return -1; // Target not found
}

void deleteNode(struct LinkedList *list, int target) {
    struct Node *current = list->head;
    struct Node *prev = NULL;

    while (current != NULL) {
        if (current->data == target) {
            if (prev == NULL) {
                list->head = current->next;
            } else {
                prev->next = current->next;
            }
            free(current);
            return;
        }
        prev = current;
        current = current->next;
    }
}

int main() {
    struct LinkedList myList;
    initializeList(&myList);

    insertNode(&myList, 10);
    insertNode(&myList, 20);
    insertNode(&myList, 30);

    displayList(&myList);

    int target = 20;
    int position = searchNode(&myList, target);

    if (position != -1) {
        printf("%d found at position %d.\n", target, position);
    } else {
        printf("%d not found in the list.\n", target);
    }

    deleteNode(&myList, target);
    displayList(&myList);

    return 0;
}

以上代码演示了单链表的新建、查找、删除操作。

3.4 栈与队列

3.4.1 什么是栈?

栈是一种具有后进先出(LIFO)特性的数据结构,只允许在栈顶进行插入和删除操作。

3.4.1.1 栈的实现示例
#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 5

struct Stack {
    int items[MAX_SIZE];
    int top;
};

void initializeStack(struct Stack *stack) {
    stack->top = -1;
}

int isFull(struct Stack *stack) {
    return stack->top == MAX_SIZE - 1;
}

int isEmpty(struct Stack *stack) {
    return stack->top == -1;
}

void push(struct Stack *stack, int element) {
    if (!isFull(stack)) {
        stack->top++;
        stack->items[stack->top] = element;
    } else {
        printf("Stack is full. Cannot push element.\n");
    }
}

int pop(struct Stack *stack) {
    if (!isEmpty(stack)) {
        int poppedElement = stack->items[stack->top];
        stack->top--;
        return poppedElement;
    } else {
        printf("Stack is empty. Cannot pop element.\n");
        return -1; // Placeholder
    }
}

int peek(struct Stack *stack) {
    if (!isEmpty(stack)) {
        return stack->items[stack->top];
    } else {
        printf("Stack is empty. Cannot peek.\n");
        return -1; // Placeholder
    }
}

void displayStack(struct Stack *stack) {
    printf("Stack: ");
    for (int i = 0; i <= stack->top; i++) {
        printf("%d ", stack->items[i]);
    }
    printf("\n");
}

int main() {
    struct Stack myStack;
    initializeStack(&myStack);

    push(&myStack, 10);
    push(&myStack, 20);
    push(&myStack, 30);

    displayStack(&myStack);

    printf("Top element: %d\n", peek(&myStack));

    pop(&myStack);
    displayStack(&myStack);

    return 0;
}

以上代码演示了栈的实现,包括初始化、压栈、弹栈、查看栈顶元素和显示栈内容。

3.4.2 什么是队列?

队列是一种具有先进先出(FIFO)特性的数据结构,只允许在队尾插入元素,在队头删除元素。

3.4.2.1 队列的实现示例
#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 5

struct Queue {
    int items[MAX_SIZE];
    int front;
    int rear;
};

void initializeQueue(struct Queue *queue) {
    queue->front = -1;
    queue->rear = -1;
}

int isFullQ(struct Queue *queue) {
    return (queue->rear == MAX_SIZE - 1 && queue->front == 0) || (queue->rear == queue->front - 1);
}

int isEmptyQ(struct Queue *queue) {
    return queue->front == -1;
}

void enqueue(struct Queue *queue, int element) {
    if (!isFullQ(queue)) {
        if (isEmptyQ(queue)) {
            queue->front = 0;
        }
        queue->rear = (queue->rear + 1) % MAX_SIZE;
        queue->items[queue->rear] = element;
    } else {
        printf("Queue is full. Cannot enqueue element.\n");
    }
}

int dequeue(struct Queue *queue) {
    if (!isEmptyQ(queue)) {
        int dequeuedElement = queue->items[queue->front];
        if (queue->front == queue->rear) {
            queue->front = -1;
            queue->rear = -1;
        } else {
            queue->front = (queue->front + 1) % MAX_SIZE;
        }
        return dequeuedElement;
    } else {
        printf("Queue is empty. Cannot dequeue element.\n");
        return -1; // Placeholder
    }
}

void displayQueue(struct Queue *queue) {
    printf("Queue: ");
    int i = queue->front;
    while (i != -1) {
        printf("%d ", queue->items[i]);
        if (i == queue->rear) {
            break;
        }
        i = (i + 1) % MAX_SIZE;
    }
    printf("\n");
}

int main() {
    struct Queue myQueue;
    initializeQueue(&myQueue);

    enqueue(&myQueue, 10);
    enqueue(&myQueue, 20);
    enqueue(&myQueue, 30);

    displayQueue(&myQueue);

    dequeue(&myQueue);
    displayQueue(&myQueue);

    return 0;
}

以上代码演示了队列的实现,包括初始化、入队、出队和显示队列内容。

3.5 二叉树的建树和遍历

3.5.1 什么是二叉树?

二叉树是一种树型结构,每个节点最多有两个子节点,分别为左子节点和右子节点。

3.5.1.1 二叉树的建树和遍历示例
#include <stdio.h>
#include <stdlib.h>

struct TreeNode {
    int data;
    struct TreeNode *left;
    struct TreeNode *right;
};

struct TreeNode *createNode(int data) {
    struct TreeNode *newNode = (struct TreeNode *)malloc(sizeof(struct TreeNode));
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

struct TreeNode *buildTree() {
    struct TreeNode *root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);
    root->right->left = createNode(6);
    root->right->right = createNode(7);
    return root;
}

void inorderTraversal(struct TreeNode *root) {
    if (root != NULL) {
        inorderTraversal(root->left);
        printf("%d ", root->data);
        inorderTraversal(root->right);
    }
}

void preorderTraversal(struct TreeNode *root) {
    if (root != NULL) {
        printf("%d ", root->data);
        preorderTraversal(root->left);
        preorderTraversal(root->right);
    }
}

void postorderTraversal(struct TreeNode *root) {
    if (root != NULL) {
        postorderTraversal(root->left);
        postorderTraversal(root->right);
        printf("%d ", root->data);
    }
}

int main() {
    struct TreeNode *root = buildTree();

    printf("Inorder Traversal: ");
    inorderTraversal(root);
    printf("\n");

    printf("Preorder Traversal: ");
    preorderTraversal(root);
    printf("\n");

    printf("Postorder Traversal: ");
    postorderTraversal(root);
    printf("\n");

    return 0;
}

以上代码演示了二叉树的建树和三种遍历方式(中序、前序、后序)。

3.6 考研必会的查找算法

3.6.1 二分查找算法

二分查找算法是一种高效的查找方法,适用于有序数组。

3.6.1.1 二分查找算法示例
#include <stdio.h>

int binarySearch(int arr[], int low, int high, int target) {
    while (low <= high) {
        int mid = low + (high - low) / 2;

        if (arr[mid] == target) {
            return mid; // 找到目标,返回索引
        } else if (arr[mid] < target) {
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }

    return -1; // 目标不存在,返回-1
}

int main() {
    int sortedArray[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int target = 7;
    int arraySize = sizeof(sortedArray) / sizeof(sortedArray[0]);

    int result = binarySearch(sortedArray, 0, arraySize - 1, target);

    if (result != -1) {
        printf("%d found at index %d.\n", target, result);
    } else {
        printf("%d not found in the array.\n", target);
    }

    return 0;
}

以上代码演示了二分查找算法的实现和应用。

3.7 考研必会的排序算法(上)

3.7.1 插入排序算法

插入排序算法是一种简单直观的排序方法,适用于小规模数据或基本有序的数据。

3.7.1.1 插入排序算法示例
#include <stdio.h>

void insertionSort(int arr[], int size) {
    int i, key, j;

    for (i = 1; i < size; i++) {
        key = arr[i];
        j = i - 1;

        // 将比key大的元素往后移动
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }

        arr[j + 1] = key;
    }
}

int main() {
    int array[] = {12, 11, 13, 5, 6};
    int arraySize = sizeof(array) / sizeof(array[0]);

    insertionSort(array, arraySize);

    printf("Sorted array: ");
    for (int i = 0; i < arraySize; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    return 0;
}

以上代码演示了插入排序算法的实现和应用。

3.8 考研必会的排序算法(下)

3.8.1 冒泡排序算法

冒泡排序算法是一种基础的排序方法,通过多次交换相邻元素的位置,将最大(或最小)的元素逐步移动到最右侧。

3.8.1.1 冒泡排序算法示例
#include <stdio.h>

void bubbleSort(int arr[], int size) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = 0; j < size - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                // 交换相邻元素
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

int main() {
    int array[] = {64, 34, 25, 12, 22, 11, 90};
    int arraySize = sizeof(array) / sizeof(array[0]);

    bubbleSort(array, arraySize);

    printf("Sorted array: ");
    for (int i = 0; i < arraySize; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    return 0;
}

以上代码演示了冒泡排序算法的实现和应用。

3.9 排序算法真题实战

3.9.1 题目描述

实现一个排序算法,要求具有良好的时间复杂度和稳定性。

3.9.2 解题思路

考虑使用归并排序,它具有稳定性和O(n log n)的时间复杂度。

3.9.2.1 归并排序算法示例
#include <stdio.h>
#include <stdlib.h>

void merge(int arr[], int left, int mid, int right) {
    int i, j, k;
    int n1 = mid - left + 1;
    int n2 = right - mid;

    // 创建临时数组
    int *leftArray = (int *)malloc(n1 * sizeof(int));
    int *rightArray = (int *)malloc(n2 * sizeof(int));

    // 将数据复制到临时数组 leftArray[] 和 rightArray[]
    for (i = 0; i < n1; i++) {
        leftArray[i] = arr[left + i];
    }
    for (j = 0; j < n2; j++) {
        rightArray[j] = arr[mid + 1 + j];
    }

    // 归并临时数组到 arr[left..right]
    i = 0;
    j = 0;
    k = left;
    while (i < n1 && j < n2) {
        if (leftArray[i] <= rightArray[j]) {
            arr[k] = leftArray[i];
            i++;
        } else {
            arr[k] = rightArray[j];
            j++;
        }
        k++;
    }

    // 将剩余元素复制到 arr[]
    while (i < n1) {
        arr[k] = leftArray[i];
        i++;
        k++;
    }
    while (j < n2) {
        arr[k] = rightArray[j];
        j++;
        k++;
    }

    // 释放临时数组内存
    free(leftArray);
    free(rightArray);
}

void mergeSort(int arr[], int left, int right) {
    if (left < right) {
        // 计算中间点
        int mid = left + (right - left) / 2;

        // 递归排序左半部分和右半部分
        mergeSort(arr, left, mid);
        mergeSort(arr, mid + 1, right);

        // 合并两部分
        merge(arr, left, mid, right);
    }
}

int main() {
    int array[] = {12, 11, 13, 5, 6, 7};
    int arraySize = sizeof(array) / sizeof(array[0]);

    mergeSort(array, 0, arraySize - 1);

    printf("Sorted array: ");
    for (int i = 0; i < arraySize; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    return 0;
}

以上代码演示
了归并排序算法的实现和应用。

4. 低级编程与汇编语言

4.1 数据的机器级表示

4.1.1 什么是机器级表示?

机器级表示指的是数据在计算机内部的二进制表示形式。理解机器级表示对于深入了解计算机底层运行原理至关重要。

4.1.2 二进制和十进制的转换
  • 二进制转十进制: 将二进制数每位上的数值与2的幂相乘,然后相加得到十进制数。
  • 十进制转二进制: 使用除2取余法,将余数逆序排列。
4.1.2.1 二进制和十进制转换示例
#include <stdio.h>

// 二进制转十进制
int binaryToDecimal(long long binary) {
    int decimal = 0, i = 0, remainder;
    while (binary != 0) {
        remainder = binary % 10;
        binary /= 10;
        decimal += remainder * (1 << i);
        ++i;
    }
    return decimal;
}

// 十进制转二进制
long long decimalToBinary(int decimal) {
    long long binary = 0;
    int remainder, i = 1, step = 1;

    while (decimal != 0) {
        remainder = decimal % 2;
        decimal /= 2;
        binary += remainder * i;
        i *= 10;
    }

    return binary;
}

int main() {
    long long binaryNumber;
    printf("Enter a binary number: ");
    scanf("%lld", &binaryNumber);
    printf("%lld in binary = %d in decimal\n", binaryNumber, binaryToDecimal(binaryNumber));

    int decimalNumber;
    printf("Enter a decimal number: ");
    scanf("%d", &decimalNumber);
    printf("%d in decimal = %lld in binary\n", decimalNumber, decimalToBinary(decimalNumber));

    return 0;
}

以上代码演示了二进制和十进制之间的转换。

4.2 汇编语言零基础入门

4.2.1 什么是汇编语言?

汇编语言是一种低级别的编程语言,它使用符号和助记符来代替机器语言指令,更接近硬件层面。

4.2.2 汇编语言基础指令
  • MOV: 将数据从一个地方移动到另一个地方。
  • ADD: 将两个数相加。
  • SUB: 从一个数中减去另一个数。
  • JMP: 无条件跳转。
  • CMP: 比较两个数。
4.2.2.1 汇编语言基础指令示例
section .data
    msg db 'Hello, World!', 0

section .text
    global _start

_start:
    ; write system call
    mov eax, 4
    mov ebx, 1
    mov ecx, msg
    mov edx, 13
    int 0x80

    ; exit system call
    mov eax, 1
    xor ebx, ebx
    int 0x80

以上汇编代码实现了在屏幕上输出"Hello, World!"。这是一个Linux x86汇编代码示例。

4.3 汇编语言考研真题实战

4.3.1 题目描述

编写一个汇编程序,实现对数组的排序功能。

4.3.2 解题思路

考虑使用经典的排序算法,如冒泡排序或插入排序,编写相应的汇编代码实现排序。

4.3.2.1 汇编排序程序示例
section .data
    array dd 5, 2, 8, 1, 6, 3, 7, 4 ; 示例数组

section .text
    global _start

_start:
    ; 调用排序函数
    mov eax, array
    mov ebx, 8
    call bubbleSort

    ; 在此添加打印数组的代码(根据实际需要)

    ; exit system call
    mov eax, 1
    xor ebx, ebx
    int 0x80

bubbleSort:
    ; 参数:
    ; eax - 数组首地址
    ; ebx - 数组长度

    ; 在此添加冒泡排序汇编代码

    ret

以上汇编代码演示了如何调用冒泡排序函数对数组进行排序。在真实的情况下,需要根据实际需要进行适当的修改。

5. 文件操作

5.1 文件的操作C语言实战

5.1.1 文件操作基础

C语言中文件操作通过FILE结构和相关的库函数实现,包括fopenfclosefprintf

#include <stdio.h>

int main() {
    // 文件指针
    FILE *file;

    // 打开文件
    file = fopen("example.txt", "w");

    if (file == NULL) {
        printf("Unable to open the file.\n");
        return 1;
    }

    // 写入数据到文件
    fprintf(file, "Hello, File!\n");

    // 关闭文件
    fclose(file);

    return 0;
}

以上代码演示了如何打开文件、写入数据并关闭文件。该程序将字符串"Hello, File!"写入名为"example.txt"的文件。

在实际应用中,需要注意文件是否成功打开(判空)以及文件操作是否成功。此外,对于读取文件和其他更复杂的文件操作,还可以使用fscanf等函数。

总结

在本文中,我们涵盖了计算机基础的核心概念,从C语言的基础语法到数据结构与算法的实战应用,再到低级编程和汇编语言的初步了解。通过系统的学习路径,读者将建立起对计算机底层运行原理的深刻理解,并具备实际编程的能力。希望本文能够为初学者提供清晰的指引,使他们能够更自信、更熟练地处理计算机科学领域的挑战。

文章来源:https://blog.csdn.net/qq_42531954/article/details/135653819
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。