C语言练习题(16) 指出下列代码的缺陷【多选】( ) (非常详细的讲解)

1:指出下列代码的缺陷【多选】( )

float f[10];
// 假设这里有对f进行初始化的代码
for(int i = 0; i < 10;)
{
if(f[++i] == 0)
break;
}

A: for(int i = 0; i < 10;)这一行写错了 B: f是float型数据直接做相等判断有风险
C: f[++i]应该是f[i++] D: 没有缺陷


解析 BC

B:浮点型的0不是真正的0,而是类似0.00000001或者0.07这样的近似数,这样的值跟0比较的话是不相等的,也就是说0!=0.

在C语言中,应该使用浮点数的绝对值之差小于一个极小的数来判断浮点数是否相等。浮点数计算的误差使得直接判断两个浮点数是否相等并不可靠,因此需要引入一个极小的数作为误差范围。一种常用的方式是使用浮点数的绝对值之差小于一个很小的数epsilon来进行判断

C选项错,是因为++i会导致数组下标越界异常

浮点数的判断方法,例如:

#include 
#include 

int main()
 {
    double a = 1.0 / 3.0;
    double b = 0.333333;
    double epsilon = 0.000001; // 设置一个很小的误差范围
    if (fabs(a - b) < epsilon) 
    {
        printf("a and b 是近似相等的.\n");
    } 
    else 
    {
        printf("a and b 是不相等的.\n");
    }
    return 0;
}

2:请指出以下程序的错误【多选】( )

void GetMemory(char **p, int num)
{
if(NULL == p && num <= 0)//1
return;
*p = (char*)malloc(num);
return;
} 
int main()
{
char *str = NULL;
GetMemory(&str, 80); //2
if(NULL != str)
{
strcpy(&str, "hello"); //3
printf(str); //4
} 
return 0;
}

A: 1 B: 2 C: 3 D: 4

解析 ACD

A:在 GetMemory 函数中,如果传入的 p 参数是NULL,那么代码就会出现问题,因为无法通过空指针来修改指向的内存地址,这样会导致程序崩溃。

应改为:if(p == NULL || num <= 0)

C:strcpy(&str,“hello”); // 应为 strcpy(str,“hello”);
D:改为return true; // return 0是int类型与void冲突

3:请问下列代码的输出结果有可能是哪些【多选】( )

#include 
typedef union
{
int a;
struct
{
short b;
short c;
};
}X;
int main()
{
X x;
x.a = 0x20150810;
printf("%x,%x\n", x.b, x.c);
return 0;
}

A: 2015,810 B: 50810,201 C: 810,2015 D:`20150,810

解析 AC

①在这段代码中,定义了一个联合类型X,它包含了一个整型变量a和一个结构体(struct)变量,结构体中包含了两个short类型的成员变量b和c。在main函数中,声明了一个X类型的变量x。将整型变量x.a的值设置为0x20150810,
②这个值的二进制表示为: 0010 0000 0001 0101 000 1000000,对应于b和c两个short类型的成员变量的值。

使用printf函数打印x.b和x.c的值,%x用于输出十六进制数的格式。返回0,表示程序执行完毕。

运行这段代码,会输出x.b和x.c的值,具体输出取决于机器的字节序(大端序或小端序)。对于大端序的机器,输出结果为b=2015,c=81;对于小端序的机器,输出结果为b=81,c=2015。

这段代码主要通过联合类型的特性,将整型变量的二进制表示解析为两个short类型的成员变量的值,并打印出来。

0x20150810如果按照大端模式存储:
从低地址到高地址:20 15 08 10
输出从低地址到高地址:20 15 08 10
如果按照小端模式存储:
从低地址到高地址:10 08 15 20
输出从高地址到低地址:08 10 20 15

其中一个地址占个字节

4:下面这个程序执行后会有什么错误或者效果【多选】( )

#define MAX 255
int main()
{
unsigned char A[MAX], i;
for(i = 0; i <= MAX; i++)
A[i] = i;
return 0;
}

A: 数组越界 B: 死循环 C: 栈溢出 D: 内存泄露

解析 AB

A: 数组越界 :
在循环中,i的取值范围是从0到MAX(包括MAX),但是数组A的大小是MAX,即255。当i达到255时,会尝试访问A[255],这是超出数组的范围,会导致数组越界错误。

B:死循环:
i是一个无符号整型 当i=255时,i的原码为00000000 00000000 00000000 11111111
char类型只能储存8个即 11111111 循环中的条件 i <= MAX 是无符号char类型的取值范围。当 i 达到 MAX=255时,由于无符号char类型的特性,i+1 将会变为 0,导致循环继续执行。这将导致无限循环,无法跳出循环。

5:请问下列程序的输出是多少( )

#include
int main()
{
unsigned char i = 7;
int j = 0;
for(;i > 0;i -= 3)
{
++j;
}
printf("%d\n", j);
return 0;
}

A: 2 B: 死循环 C: 173 D: 172

解析 C
我们要知道无符号类型的i,它的范围时0~255,与上题考的是一个知识点。

这题正着推不容易,可以考虑反着推
要想退出循环 最后必定是 i=0 根据选项
A: (0 + 23) % 256 = 6 不是7 , 所以A错误
C: (0 + 173
3) % 256 = 7 , 所以C可以
D: (0 + 172*3) % 256 = 4 不是7,所以D错误
B: 既然C可以,当然B就错误

6:牛牛以前在老师那里得到了一个正整数数对(x, y), 牛牛忘记他们具体是多少了。但是牛牛记得老师告诉过他x和y均不大于n, 并且x除以y的余数大于等于k。牛牛希望你能帮他计算一共有多少个可能的数对。

输入描述:
输入包括两个正整数n,k(1 <= n <= 10^5, 0 <= k <= n - 1)。
输出描述:
对于每个测试用例, 输出一个正整数表示可能的数对数量。
示例1
输入:5 2
输出:7
说明:满足条件的数对有(2,3),(2,4),(2,5),(3,4),(3,5),(4,5),(5,3)

#define _CRT_SECURE_NO_WARNINGS 1
#include 
int main()
{
    long n, k = 0;
    long count = 0;
    scanf("%ld %ld", &n, &k);
    if (k == 0)
    {
        printf("%ld\n", n * n);
        goto end;
    }
    for (long j = k + 1; j <= n; j++)
    {
        long help = n % j < k ? 0 : (n % j) - k + 1;
        count = count + (j - k) * (n / j) + help;
    }
    printf("%ld\n", count);
end:
    return 0;
}

解析

首先从输入中读取两个长整型变量n和k,并初始化一个长整型变量count为0。然后进行判断,如果k等于0,则直接输出n的平方,并跳转到标签end。接下来,通过一个循环遍历范围从k+1到n的所有整数j。在每次循环中,计算n%j减去k加1(如果n%j大于等于k的话),赋值给辅助变量help。然后将(j-k)*(n/j)的结果加上help,累加到count中。最后输出count的值。注意,在代码末尾使用了goto语句来跳转到标签end并返回0,这是为了避免在if语句中再次输出count的值。

原理:

用普通的遍历是没办法走到最后的,数据一但非常大时,时间复杂度就会报错,这里就需要推导一下数学公式:(n / y) * (y - k) +((n % y < k) ? 0, (n % y - k + 1));

① 当 y <=k 时,意味着任何数字取模y的结果都在 [0, k-1]之间,都是不符合条件的。

②当 y = k+1=4 时,x符合条件的数字有 3,7

③当 y = k+2=5 时,x符合条件的数字有 3,4,8,9

④当 y = k+3=6 时,x符合条件的数字有 3,4,5,9,10

⑤当 y = k+n时,x小于y当前值,且符合条件的数字数量是:y-k个,x大于y当前值,小于2*y的数据中,且符合条件的数字数量是:y-k个

从上一步能看出来,在y的整数倍区间内,x符合条件的数量就是 (n / y) * (y - k)个

n / y 表示有多少个完整的 0 ~ y区间, y - k 表示有每个区间内有多少个符合条件的数字

最后还要考虑的是6…往后这种超出倍数区间超过n的部分的统计

n % y 就是多出完整区间部分的数字个数,其中k以下的不用考虑,则符合条件的是 n % y - (k-1) 个

这里需要注意的是类似于9这种超出完整区间的数字个数 本就小于k的情况,则为0

7:输入一个字符串和一个整数 k ,截取字符串的前k个字符并输出

数据范围:字符串长度满足 1≤n≤1000 , 1≤k≤n
输入描述:
1.输入待截取的字符串
2.输入一个正整数k,代表截取的长度
输出描述:截取后的字符串
示例1
输入:
abABCcDEF
6
输出:abABCc

示例2
输入:
bdxPKBhih
6
输出:bdxPKB

#include 
int main() 
{
    char arr[1001]={0};
    int k;
    scanf("%s\n",arr);
    scanf("%d",&k);
    for (int i=0;i<k;i++)
    {
        printf("%c",arr[i]);
    }
    return 0;
}

这道题就很简单了,相信大家都用不到解析吧。

解析

主函数首先声明了一个字符数组arr,大小为1001,并初始化为0。然后通过scanf函数从标准输入读取一个字符串到arr中,并使用换行符\n作为输入结束的标志。接着,再通过scanf函数从标准输入读取一个整数到变量k中。

接下来的for循环用于打印出字符串arr中前k个字符。循环变量i从0开始,每次循环打印arr[i]的值,然后增加i的值,直到循环结束。

最后,主函数返回0,表示程序正常结束。

你可能感兴趣的:(c语言,算法,数据结构)