二级C语言2024-3易错题

news/2024/9/20 22:51:32 标签: c语言, 开发语言

1 结构

一个C语言程序是由( )。

A. 一个主程序和若干子程序组成
B. 函数组成
C. 若干过程组成
D. 若干子程序组成

一个C语言程序是由多个部分组成的,其中最核心的部分是函数。在C语言中,函数是实现特定功能的代码块,它们可以被重复调用以执行相同的任务。因此,选项B是正确的。

而一个程序可能包含多个函数


2 输出相关

下列叙述中正确的是( )。

A. 调用printf()函数时,必须要有输出项
B. 使用putchar()函数时,必须在之前包含头文件stdio.h
C. 在C语言中,整数可以以二进制、八进制或十六进制的形式输出
D. 调节getchar()函数读入字符时,可以从键盘上输入字符所对应的ASCII码

正确答案:B
关于C语言中的输入和输出函数,以下是对各选项的解释:

  • A.
    错误。printf()函数可以没有输出项,例如,printf(“Hello, world!\n”); 中的 “Hello, world!” 就是一个输出项,它可以输出字符。 但这样的一种情况 printf(“”); 是合法的,只是它什么都不输出。
  • B.
    正确。putchar() 函数是标准库函数,它是定义在 stdio.h 中的。因此要使用 putchar(),必须包含头文件 stdio.h。正确的写法如下:
#include <stdio.h>

int main() {
   putchar('A');
   return 0;
}
  • C.
    错误。C语言中的标准库函数 printf 并不直接支持二进制输出。整数可以使用八进制和十六进制的形式输出,但必须通过合适的格式控制符,例如,基于八进制使用 %o,基于十六进制使用 %x 或 %X。C语言中没有直接的格式化控制符来输出二进制。不过可以通过一定的逻辑实现二进制输出。
  • D.
    错误。getchar() 函数从标准输入读取下一个字符,并返回该字符的ASCII值。如果说”调节getchar()函数读入字符时,可以从键盘上输入字符所对应的ASCII码“,意思是要把字符转换成它的ASCII码来输入,这是不符合实际操作的。实际操作是直接输入字符,由getchar()捕获。例如输入 A 则 getchar() 返回 65(这是A的ASCII值)。

所以,正确答案是 B。


3 字符串比较

下述语句中,在字符串s1和s2相等时显示"they are Equal"的是( )。

A. if(*s1==*s2) puts(“they are Equal”);
B. if(!strcmp(s1,s2)) puts(“they are Equal”);
C. if(s1==s2) Puts(“they are Equal”);
D. if(strcmp(s1,s2)) puts(“they are Equal”);

正确答案 B.

  • A.
    这个条件仅比较了s1和s2的第一个字符是否相等。
  • C.
    这里使用的是直接指针比较(s1 == s2),它检查的是s1和s2这两个指针是否指向内存中的同一个地址,而不是比较它们所指向的内容是否相等。

strcmp

strcmp 是 C 语言标准库中的一个函数,用于比较两个字符串。它位于 <string.h> 头文件中。这个函数通过逐字节比较两个字符串来判断它们是否相等以及它们之间的顺序关系。下面是 strcmp 函数的一些关键点:

函数原型
int strcmp(const char *s1, const char *s2);
参数:

s1: 指向第一个要比较的以空字符终止的字符串。
s2: 指向第二个要比较的以空字符终止的字符串。

返回值:
  • 如果 s1 和 s2 完全相同,则返回 0。
  • 如果 s1 小于 s2(根据字典序),则返回一个小于 0 的整数。
  • 如果 s1 大于 s2(根据字典序),则返回一个大于 0 的整数。

这里的“小于”和“大于”是基于 ASCII 值进行比较的。例如,在 ASCII 中,大写字母 ‘A’ 到 ‘Z’ 的值小于小写字母 ‘a’ 到 ‘z’ 的值。


4 函数指针

给定程序中,函数fun的功能是用函数指针指向要调用的函数,并进行调用。规定在__2__处使fa指向函数f1,在__3__处使fb指向函数f2。当调用正确时,程序输出:

x1=5.000000,x2=3.000000,x1x1+x1x2=40.000000

请在程序的下划线处填入正确的内容并把下划线删除,使程序得出正确的结果。

注意:源程序存放在考生文件夹下的BLANK.C中。

不得增行或删行,也不得更改程序的结构!

给定源程序:

#include  <stdio.h>
double f1(double x)
{return x*x;}
double f2(double x, double y)
{return x*y;}
double fun(double a, double b)
{
/**********found**********/
  __1__ (*f)();
  double r1, r2;
/**********found**********/
  f = __2__ ;   /* point fountion f1 */
  r1 = f(a);
/**********found**********/
  f = __3__ ;   /* point fountion f2 */
  r2 = (*f)(a, b);
  return r1 + r2;
}
main()
{double x1=5, x2=3, r;
  r = fun(x1, x2);
  printf("\nx1=%f, x2=%f, x1*x1+x1*x2=%f\n",x1, x2, r);
}

函数指针的基础

声明函数指针

在C/C++中,声明一个函数指针需要遵循一定的语法格式,因为这关系到函数返回类型以及参数类型的准确性。最基本的格式如下:

返回类型 (*指针名称)(参数类型1, 参数类型2, ...);

例如,对于一个无参数且返回值为void的函数,函数指针的声明如下:

void (*funcPtr)();

而对于一个有两个int参数并返回int的函数,声明如下:

int (*func_ptr)(int, int);
函数指针的初始化

函数指针可以通过将函数的名称(函数名在程序中作为它的地址)赋值给它来初始化:

int add(int a, int b) {
    return a + b;
}

int (*func_ptr)(int, int) = add;

//或者可以采用另一种方式,先声明后赋值:
int (*func_ptr)(int, int);
func_ptr= add;
使用函数指针
  • 通过指针调用函数
    初始化后,你就可以通过函数指针调用函数了:

  • 使用函数指针调用函数
    一旦函数指针指向了一个具体的函数,我们就可以使用 (*指针变量名)(参数列表) 的形式来通过该指针调用函数。

int result = (*func_ptr)(3, 4); // 调用 add 函数,传入参数 3 和 4
//或者,由于函数指针的语法糖,我们也可以这样写:
int result = func_ptr(3, 4); // 同样调用 add 函数

int result = add(3, 4);
函数指针作为参数

函数指针可以作为参数传递给其他函数,这是编写回调函数的一种常用方法:

实现简易的计算函数:

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int calculate(int a, int b, int (*operation)(int, int)) {
    return operation(a, b);
}

int main() {
    int a = 5, b = 3;
    printf("Add: %d\n", calculate(a, b, add));
    printf("Subtract: %d\n", calculate(a, b, subtract));
    return 0;
}

排序:

#include <stdio.h>

// 比较函数原型可以留空,因为在你的示例中并未直接使用到这个函数
int compare(int a, int b);

// 排序函数,接受一个数组、数组长度和一个比较函数指针
void sort(int *array, int length, int (*compare_func)(int, int)) {
    for (int i = 0; i < length - 1; ++i) {
        for (int j = 0; j < length - 1 - i; ++j) {
            if (compare_func(array[j], array[j + 1]) > 0) {
                // 交换元素
                int temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
            }
        }
    }
}

// 比较函数,用于升序排序
int ascending(int a, int b) {
    return a - b;
}

// 比较函数,用于降序排序
int descending(int a, int b) {
    return b - a;
}

int main() {
    int numbers[] = {5, 2, 9, 1, 5, 6};
    int length = sizeof(numbers) / sizeof(numbers[0]);

    // 使用升序比较函数进行排序
    sort(numbers, length, ascending);
    printf("Ascending order: ");
    for (int i = 0; i < length; i++) {
        printf("%d ", numbers[i]);
    }
    printf("\n");

    // 重新排序为降序,需重新赋初值
    for (int i = 0; i < length; i++) {
        numbers[i] = {5, 2, 9, 1, 5, 6}; // 若想重复上述数组,需要重新设置此数组的值
    }
    
    // 使用降序比较函数进行排序
    sort(numbers, length, descending);
    printf("Descending order: ");
    for (int i = 0; i < length; i++) {
        printf("%d ", numbers[i]);
    }
    printf("\n");

    return 0;
}
函数指针的应用场景
  • 回调函数:函数指针让我们在运行时决定调用哪个函数,这对于实现回调函数机制非常有用。
  • 状态机:在状态机模式中,函数指针可以用来表示不同状态下的行为。
  • 简化函数列表:通过函数指针数组,可以简化对一组函数的引用和管理。
  • 提高性能:在某些情况下,函数指针可以减少函数调用的开销,尤其是在循环内部调用时。
注意事项
  • 类型安全:确保函数指针类型与其指向的函数原型完全匹配,否则会导致不可预期的错误。
  • 空指针风险:未初始化的函数指针或被故意设置为NULL(或nullptr)的函数指针在使用前应该总是被检查是否为空,以避免运行时错误。
  • 可读性和复杂性:虽然函数指针非常强大,但它们也会增加代码的复杂性。明智的做法是在需要它们的强大功能时才使用它们。
C++中的额外考量

在C++中,函数指针仍然有其用途,但是现代C++越来越倾向于使用std::function和lambda表达式来实现类似的功能,这些方法提供了更好的类型安全和异常安全性。

#include <functional>
#include <iostream>

int add(int a, int b) {
    return a + b;
}

int main() {
    std::function<int(int, int)> func = add;
    std::cout << "Add Result: " << func(3, 4) << std::endl;

    auto multiply = [](int x, int y) { return x * y; };
    std::cout << "Multiply Result: " << multiply(3, 4) << std::endl;

    return 0;
}

std::function是C++11引入的一个类模板,能封装任何可调用的对象(包括函数指针、成员函数指针、甚至functor),提供了一个相对安全的调用方式。Lambda表达式则提供了一种便捷的方式来定义匿名函数。

总结来说,函数指针是C和C++中一种强大的特性,它为软件设计提供了灵活性,特别是在需要动态行为选择的场合。然而,随着C++的发展,一些更安全、更现代的替代方案正在变得流行。


写在后面的话

这套卷子就分析到这里,说实话,现在和几年前已经不是一个时代了。在如今这个时代,拥抱大模型是大势所趋。放在以前,想查找一些资料,一般就是上网自行查找,到书上找,或者向他人请教,但现在只需要打开网页,随便搜索一个大模型就能提问,甚至部分浏览器也集成了大模型,搜索时还会自动帮你总结整理,十分方便!


http://www.niftyadmin.cn/n/5667802.html

相关文章

AI免费UI页面生成

https://v0.dev/chat v0 - UI设计 cursor - 编写代码 参考&#xff1a;https://www.youtube.com/watch?vIyIVvAu1KZ4 界面和claude类似&#xff0c;右侧展示效果和代码 https://pagen.so/

(c++)线程的创建、互斥锁的使用、线程数组

1.创建10个线程&#xff0c;每个线程都做10万次全局变量num1操作&#xff0c;然后输出这个全局变量&#xff0c;预想结果应该是100万。但是线程可能在cpu分配的一个时间片中做不完10万次1的操作&#xff0c;这时候cpu会被其他线程抢占&#xff0c;由于num1不是一个原子操作&…

jQuery 简介 ③ ready()事件函数、jQuery 二个原则及容错机制

文章目录 jQuery 简介 ③五、ready() 准备就绪时执行代码六、jQuery 核心1、Get and Set in One 原则2、Get first Set all 原则3、容错机制:jQuery 简介 ③ 五、ready() 准备就绪时执行代码 如果我们在中引入jQuery库文件,并编写相应的jQuery代码来操作DOM元素。这很可能导…

24.9.18学习笔记

序列模型是一种专门用于处理序列数据的机器学习模型。序列数据的特点是其中的数据点之间存在明确的顺序关系或依赖性。这种类型的模型在诸如自然语言处理&#xff08;NLP&#xff09;、语音识别、时间序列预测等领域有着广泛的应用。下面我将详细介绍几种常见的序列模型及其工作…

旋转矩阵乘法,自动驾驶中的点及坐标系变换推导

目录 1. 矩阵乘法的内项相消 2. 左右乘&#xff0c;内外旋与动静坐标系 3. 点变换 3.1 点旋转后的点坐标表示 3.2 坐标系旋转后的点坐标表示 4. 坐标变换的实质 1. 矩阵乘法的内项相消 关于旋转变换&#xff0c;离不开矩阵的乘法&#xff0c;而矩阵乘法的物理意义和本身数…

SpringBoot v2.6.13 整合 swagger

在Spring Boot 2.6.13中整合Swagger需要以下步骤&#xff1a; 添加Swagger依赖到pom.xml&#xff1a; <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version> </d…

嵌入式Linux学习笔记(6)-线程处理、线程同步、线程池(c语言实现)

一、概述 线程是一种轻量级的并发执行的机制。线程是进程中的一个实体&#xff0c;它执行在同一进程的上下文中&#xff0c;共享同一内存空间&#xff0c;但拥有独立的栈空间。 C语言的线程使用pthread库实现&#xff0c;通过包含头文件 pthread.h 来使用相关的函数和数据类型 …

【快速笔记】freeRTOS

第十八章 低功耗Tickless模式 睡眠模式:__WFI 中断唤醒 __WFE 事件唤醒 CPU CLK关闭 停止模式&#xff1a;RAM保持 中断唤醒 当 STM32F103 处于休眠模式的时候 Cortex-M3 内核停止运行&#xff0c;但是其他外设运行正常&#xff0c; 比如 NVIC、SRAM 等。 休眠模式的功耗比其他…