【C】寒假错题总结

选择题

eg1

如下代码输出的是什么( )

char a=101;
int sum=200;
a+=27;sum+=a;
printf("%d\n",sum);

A: 327    B: 99    C: 328    D: 72

答案解析:
正确答案:D
char为有符号类型,占1个字节,也就是8位,其中最高位是符号位,取值范围为-128~127;a=101+27=128,128表示为1000 0000,作为补码放在内存中,符号位为1,在与int类型的sum进行加计算时会整型提升,高位补1,再转成原码为-128,sum=200+(-128)=72

eg2

假设函数原型和变量说明如下,则调用合法的是( )


void f(int **p);
int a[4]={1,2,3,4};
int b[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int *q[3]={b[0],b[1],b[2]};

A: f(a);    B: f(b);    C: f(q);    D: f(&a);

答案解析:
正确答案:C
A选项,f(a)传参时,a会退化成指向其首元素的地址,类型是 int*,不符。B选项,b是二维数组,传参时会退化成指向其首元素的指针,也就是b[0]的地址,b[0]的类型是int [4],故&b[0]类型是int()[4],不符。D选项,&a是数组a的地址,其类型是int()[4],不符。C选项,q是一个指针数组,在初始化时用b[0]、b[1]、b[2], 此时b[0]、b[1]、b[2]会退化成指向各首元素的指针(int* 类型,因此类型符合,可以用它们初始化)。q传参时,退化成指向其首元素的指针,即 int**,符合33

eg3

假设C语言程序里使用 malloc 申请了内存,但是没有 free 掉,那么当该进程被kill之后,操作系统会( )
A: 内存泄露 B: segmentation fault C: core dump D: 以上都不对

答案解析:
正确答案:D
不管用户程序怎么用malloc,在进程结束的时候,用户程序开辟的内存空间都将会被回收

eg4

如下程序输出的结果是什么( )


#include <stdio.h>
typedef struct List_t
{
struct List_t* next;
struct List_t* prev;
char data[0];
}list_t;
int main()
{
printf("%d",sizeof(list_t));
return 0;
}

A: 4byte    B: 8byte    C: 5byte    D: 9byte

答案解析:
正确答案:B
题目中的char data[0]或写成char data[],即为柔性数组成员;在计算机结构体大小的时候data不占用struct的空间,只是作为一个符号地址存在。因此sizeof的值是两个指针所占字节,即4+4=8字节

eg5

以下有关C语言的说法中,错误的是( )
A: 内存泄露一般是指程序申请了一块内存,使用完后,没有及时将这块内存释放,从而导致程序占用大量内存,但又不使用不释

B: 可以通过malloc(size_t)函数调用申请超过该机器物理内存大小的内存块
C: 无法通过内存释放函数free(void*)直接将某块已经使用完的内存直接还给操作系统,free函数只是将动态申请内存的使用
权释放
D: 可以通过内存分配函数malloc(size_t)直接申请物理内存

答案解析:
正确答案:D
free释放的内存不一定直接还给操作系统,可能要到进程结束才释放。malloc不能直接申请物理内存,它申请的是虚拟内存

eg6

以下代码的输出结果是( )


#include <stdio.h>
#define a 10
void foo();
int main()
{
    printf("%d..", a);
    foo();
    printf("%d", a);
    return 0;
} 
void foo()
{
#undef a
#define a 50
}
A: 10..10   B: 10..50    C: Error    D: 0

答案解析:
正确答案:A
define在预处理阶段就把main中的a全部替换为10了。另外,不管是在某个函数内,还是在函数外,define都是从定义开始直到文件结尾,所以如果把foo函数的定义放到main上面的话,则结果会是50…50

编程题

eg1

在这里插入图片描述
暴力求解:将字符串中的每个字符都与所有字符比较。,断是否相等。

int FirstNotRepeatingChar(char* str ) {
    // write code here
    for(int i = 0; i < strlen(str); i++)
    {
        int flag = 0;//判断第i个字符能否在后面找到
        for(int j = 0; j < strlen(str)-i; j++)
        {
            if(j != i && str[i] == str[j])
            {
                flag = 1;
                break;
            }
        }
        if(flag == 0)
        {
            return i;
        }
    }
    return -1;
    
}

eg2

在这里插入图片描述
解题思路
统计s中每个字符出现的次数,若s能构成回文串,最多只能容许一个字符出现的次数为奇数。

bool canPermutePalindrome(char* s){
    char a[256] = {0};
    for(int i = 0; i < strlen(s); i++)
    {
        a[s[i]]++;
    }
    int count = 0;
    for(int i = 0; i < 128; i++)
    {
        if(a[i] % 2 != 0)
        {
            count++;
        }
        if(count > 1)
        {
            return false;
        }
    }
    return true;
}

eg3

在这里插入图片描述

char* replaceSpaces(char* S, int length0)
{
    int count = 0;//计算空格出现的次数
    int afterLength = 0;//统计将空格替换为%20后的长度

    for(int i = 0; i < length0; i++)
    {
        if(S[i] == ' ')
        {
            count++;
        }
    }
    afterLength = length0 + 2 * count;
    S[afterLength] = '\0';//先设置字符串结尾标志
    int j = 1;//记录afterLenth的位置
    for(int i = length0 - 1; i >=0; i--)
    {
        if(S[i] != ' ')
        {
            S[afterLength - j] = S[i];
            j++;
        }
        else
        {
            S[afterLength - j] = '0';
            S[afterLength - j - 1] = '2';
            S[afterLength - j - 2] = '%';
            j += 3;
        }
    }
    return S;
}

eg4

在这里插入图片描述
【答案解析】:
注意:这道题是二进制的奇数位和偶数位的交换,只需要把偶数位左移一位,把奇数位右移一位即可

int exchangeBits(int num)
{
    int odd = 0b10101010101010101010101010101010;//保留偶位数
    int even = 0b01010101010101010101010101010101;//保留奇位数
    odd &= num;
    even &= num;
    return (odd >> 1) + (even << 1);
}

eg5

在这里插入图片描述

1、【答案解析】:
求一个数的阶乘中有多少个 尾数0 , 这里就需要灵活一点了 尾数0 是怎么来的?是乘以 10 来的,而 10=2*5 ,阶乘中 2 这个因子很多,但是 5 并不多,因此我们只需要统计 5 出现了多少次即可。

  • 暴力方法:遍历 5 的倍数,判断每个 5 的倍数中有多少个 5 ,比如 25=5*5 ,因此25是需要被统计两次的,这种方法直接,但是效率不高,因为当数字比较大的时候循环次数就比较多了…
  • 更优思想:以 10 的阶乘为例 10!=12345678910 ,每 5 个数字就会出现一次 5 ,所以 10 / 5 就是 5 出现的次数。
    但是特殊的是 25,125… 这种其中包含多个 5 的, 25=5
    5, 125=555… ,他们本身只被统计了一次, 25 还剩 1个乘数5 , 125 还剩 1个乘数25 ,因此这时候就需要再次除以 5 ,得到剩余 5 的个数,直到最后结果小于 5 为止
int trailingZeroes(int n)
{
    //时间复杂度O(logN)
    int count = 0;
    while(n >= 5)
    {
        count += n / 5;
        n /= 5;
    }
    return count;

    //时间复杂度O(N*logN)
    /*int count = 0;
    for(int i = 0; i <= n; i += 5)
    {
        int num = i;
        while(num > 0 && num % 5 == 0)
        {
            count++;
            num /= 5;
        }
    }
    return count;
}

eg6

在这里插入图片描述

这道题其实本身并不难,有了具体的公式直接循环往后推导就可以得到结果。但是当测试用例有多个的情况下,每次重新计算第k个数据,效率就要差很多了,毕竟每个数都要从头重新计算一遍。
因此程序进入后首先可以先生成一个较大的数列,后边测试用例中需要第几个直接取出即可

#include <stdio.h>

int main()
{
    int arr[1000000] = {1, 2};
    for(int i = 2; i < 1000000; i++)
    {
        arr[i] = (2 * arr[i - 1] + arr[i - 2]) % 32767;
    }
    int n = 0;
    scanf("%d", &n);
    int k = 0;
    while(n)
    {
        scanf("%d", &k);
        printf("%d\n", arr[k - 1]);
        n--;
    }
    return 0;
}
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小唐学渣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值