C语言:选择+编程(每日一练Day4)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: C语言:选择+编程(每日一练Day4)

选择题:

题一:

1、设变量已正确定义,以下不能统计出一行中输入字符个数(不包含回车符)的程序段是( )

A: n=0;while(ch=getchar()!='\n')n++;     B: n=0;while(getchar()!='\n')n++;
C: for(n=0;getchar()!='\n';n++);        
     D: n=0;for(ch=getchar();ch!='\n';n++);

答案解析:      

       对于for循环,其中第一项初始化表达式只执行一次,因此ch只从输入流中取一个字符,之后就再不会取字符,因此会死循环。

题二:

2、运行以下程序后,如果从键盘上输入 65 14<回车> ,则输出结果为( )
int main()
{
       int m, n;
       printf("Enter m,n;");
       scanf("%d%d", &m,&n);

while(m!=n)            //1

{

       while(m>n) m=m-n; //2
       while(n>m) n=n-m; //3
}
       printf("m=%d\n",m);
       return 0;
}

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

答案解析:

       此题技巧是耐心,考查while循环和循环嵌套的理解,初值m=65,n=14;循环1判断m!=n为真,来到循环2判断m>n为真,执行m=m-n;直到m=9,n=14;循环2结束来到循环3判断n>m为真,执行n=n-m;直到m=9,n=5;循环3结束回到循环1,如此往复直到m==n时,循环结束。

题三:

3、若运行以下程序时,从键盘输入 ADescriptor<回车> ,则下面程序的运行结果是( )
#include <stdio.h>
int main()
{
       char c;
       int v0=0,v1=0,v2=0;
do
{
       switch(c=getchar())
       {
       case'a':case'A':
       case'e':case'E':
       case'i':case'I':
       case'o':case'O':
       case'u':case'U':v1 += 1;
       default:v0+= 1;v2+=1;
       }
}while(c!='\n');
       printf("v0=%d,v1=%d,v2=%d\n",v0,v1,v2);
       return 0;
}

A: v0=7,v1=4,v2=7           B: v0=8,v1=4,V2=8

C: v0=11,v1=4,v2=11      D: v0=12,v1=4,v2=12

答案解析:

       代码switch语句中没有break,则每次找到入口进入后,顺序执行到代码块结束为止。例如当c为'A'时,从case 'A'进入,先后执行v1+=1;v0+=1;v2+=1;,而当c为'p'时,从default进入,先后执行v0+=1;v2+=1;,容易看出最终v0和v2是相等的。

题四:

4、如下函数是求两个int数字最大公约数的,指出其中存在的问题【多选】( )
int gcd(char x,char y)
{
       int min = x < y ? x : y;
       for (min = 0; min > 0; min--)
       if (x % min = 0 && y % min = 0)
       return min;
}

A: 参数类型不对 B: 循环变量min初值不对 C: 判断等于的符号不对 D: 返回类型不对

答案解析:

        1.函数实参是int,形参用char不对,会发生截断丢失数据;2.min在for循环开始时更新为0,不再是两个形参中的较小值;3.判断是否整除的时候误将==写成=赋值运算符;4.函数最终要返回一个int值,返回值类型没问题,但是这里要强调一个选项中没写出的问题,如果是牛客网上的题,会报编译错误,说该函数不是在所有情况下都有返回值,只有在if条件成立的情况下有返回值,一般在vs上这种情况能通过,编译器会给一个默认的返回值。

题五:

5、执行下面的程序段,语句3的执行次数为( )
for(i = 0; i <= n-1; i++) // (1)
for(j = n; j > i; j--) // (2)
state; // (3)

A: n(n+2)/2    B: (n-1)(n+2)/2   C: n(n+1)/2   D: (n-1)(n+2)

答案解析:        

       外循环有n次,当i=0,内循环为n次,当i=1,内循环为n-1次,当i=2时,内循环为n-2次,以此类推,总次数为n+(n-1)+(n-2)+......+2+1,就是个等差数列,等于n(n+1)/2。

编程题:

题一:错误的集合

645. 错误的集合 - 力扣(LeetCode)

示例:

输入:nums = [1,2,2,4]

输出:[2,3]

思路一:

       排序法:由于题目没有说明数组是否有序,所以需要我们自己将数组排序,才能去遍历;同时需要知道的是returnSize是指返回数组元素的个数。

第一步:使用qsort()函数将数组排序成升序

第二步:返回值数组开辟动态内存空间,否则在出函数时会释放;

第三步:定义一个数来记录数组的前一个数

第四步:遍历数组:相同记录为num[0],数组当前元素-前一个元素值大于一说明中间的就是缺的元素num[1];

第五步:如果最后一个元素不等于长度,说明最后一个就是缺的元素。

int my_cmp(const void* p1,const void* p2)
{
    return *(int*)p1 - *(int*)p2;
}
int* findErrorNums(int* nums, int numsSize, int* returnSize)
{
    //将数组进行升序排序
    qsort(nums,numsSize,4,my_cmp);
    //returnSize为返回数组元素个数
    *returnSize = 2;
    //开辟动态内存空间,否则在出函数时会释放
    int* num = (int*)malloc(sizeof(int)*2);
    //定义数组的前一个数
    int front = 0;
    //遍历数组
    for(int i = 0; i < numsSize;i++ )
    {
        //相同记录为num[0]
        if(nums[i] == front)
        {
            num[0] = nums[i];
        }
        //数组当前元素-前一个元素值大于一说明中间的就是缺的元素
        else if(nums[i] - front > 1)
        {
            num[1] = nums[i]-1;
        }
            front = nums[i];
    }
    //最后一个元素不等于长度,说明最后一个就是缺的元素
    if(nums[numsSize-1] != numsSize)
    {
        num[1] = numsSize;
    }
     return num;
}

思路二:

       使用标记的方式就可以找出重复的数字,数组中出现过哪个数字就把对应数字作为下标在对应位置1,表示已经标记出现过,如果哪个数据对应位已经置1,则表示就是重复的数字。有了重复的数字,拿 [1, n] 的总和减去去掉重复数据的数组总和就是丢失的数据。 其实使用标记法时出现的数字对应位每次 ++ ,则最后出现0次的就是丢失,出现2次的就是重复的,这样的方式也可以,不过需要多次遍历。

int* findErrorNums(int* nums, int numsSize, int* returnSize)
{
    *returnSize = 2;
    //遍历nums数组,将其中数据对应的位置1, 哪一位如果已经重置过则意味着数据重复了
    int *arr = (int *)calloc(numsSize + 1, sizeof(int));//申请numsSize个整形空间,并初始化为0
    int *ret = (int *)calloc(*returnSize, sizeof(int));//申请2个整形空间,并初始化为0
    int cur_sum = 0, old_sum = 0;
    for (int i = 0; i < numsSize; i++) {
        if (arr[nums[i]] == 1) 
        { //这个数字在上边数组的对应位置已经置过1了,则重复
            ret[0] = nums[i];//找到重复的数字
        } 
        arr[nums[i]] = 1; //将标记数组的对应数据位置1
        old_sum += i + 1; // 1~n的求和
        cur_sum += nums[i]; //当前数组中的数据求和(多了一个重复的,少了一个丢失的)
    } 
    ret[1] = old_sum - (cur_sum - ret[0]);//原始总和,减去去掉重复后的当前总和就是丢失的数字
    free(arr);
    return ret;
}

题二:密码检查

密码检查_牛客题霸_牛客网 (nowcoder.com)

示例1

输入:

1

CdKfIfsiBgohWsydFYlMVRrGUpMALbmygeXdNpTmWkfyiZIKPtiflcgppuR

输出:

YES

思路一:

       暴力的不能再暴力的方法:

第一步:创建输入密码数量的n,和字符串arr

第二步:for循环遍历,创建用于记录密码的字符是否正确count,顺便求字符串长度;

第三步:判断字符串长度是否合法;

第四步:遍历一遍字符串,格式正确就记录count

第五步:最后将字符串长度与count比较,相同“YES”,反之“NO”。

int main() 
{
    int n = 0;
    scanf("%d",&n);
    //字符串长度限制
    char arr[100] = {0};
    //密码个数
    for(int j = 0;j < n;j++)
    {
        scanf("%s",arr);
        //用于记录密码的字符是否正确
        int count =0;
        //字符串长度
        int sz = strlen(arr);
        //是否符合长度要求
        if(sz >= 8 && sz <= 100)
        {
            //遍历一遍字符串,格式正确就记录
            for(int i = 0;i < sz;i++)
            {
                if(arr[i] >= 'A' && arr[i] <='Z'||
                arr[i] >= 'a' && arr[i] <='z' ||
                arr[i] >= '0' && arr[i] <='9')
                {
                    count++;
                }
            }
        }
        //长度对比
        if(sz == count)
        {
            printf("YES\n");
        }
        else 
        {
            printf("NO\n");
        }
    }
    
    return 0;
}

本人实力有限可能对一些地方解释和理解的不够清晰,可以自己尝试读代码,或者评论区指出错误,望海涵!

感谢大佬们的一键三连! 感谢大佬们的一键三连! 感谢大佬们的一键三连!

                                             

目录
相关文章
|
1月前
|
NoSQL C语言 索引
十二个C语言新手编程时常犯的错误及解决方式
C语言初学者常遇错误包括语法错误、未初始化变量、数组越界、指针错误、函数声明与定义不匹配、忘记包含头文件、格式化字符串错误、忘记返回值、内存泄漏、逻辑错误、字符串未正确终止及递归无退出条件。解决方法涉及仔细检查代码、初始化变量、确保索引有效、正确使用指针与格式化字符串、包含必要头文件、使用调试工具跟踪逻辑、避免内存泄漏及确保递归有基准情况。利用调试器、编写注释及查阅资料也有助于提高编程效率。避免这些错误可使代码更稳定、高效。
226 12
|
2月前
|
Linux C语言
C语言 多进程编程(三)信号处理方式和自定义处理函数
本文详细介绍了Linux系统中进程间通信的关键机制——信号。首先解释了信号作为一种异步通知机制的特点及其主要来源,接着列举了常见的信号类型及其定义。文章进一步探讨了信号的处理流程和Linux中处理信号的方式,包括忽略信号、捕捉信号以及执行默认操作。此外,通过具体示例演示了如何创建子进程并通过信号进行控制。最后,讲解了如何通过`signal`函数自定义信号处理函数,并提供了完整的示例代码,展示了父子进程之间通过信号进行通信的过程。
|
2月前
|
Linux C语言
C语言 多进程编程(四)定时器信号和子进程退出信号
本文详细介绍了Linux系统中的定时器信号及其相关函数。首先,文章解释了`SIGALRM`信号的作用及应用场景,包括计时器、超时重试和定时任务等。接着介绍了`alarm()`函数,展示了如何设置定时器以及其局限性。随后探讨了`setitimer()`函数,比较了它与`alarm()`的不同之处,包括定时器类型、精度和支持的定时器数量等方面。最后,文章讲解了子进程退出时如何利用`SIGCHLD`信号,提供了示例代码展示如何处理子进程退出信号,避免僵尸进程问题。
|
2月前
|
消息中间件 Unix Linux
C语言 多进程编程(五)消息队列
本文介绍了Linux系统中多进程通信之消息队列的使用方法。首先通过`ftok()`函数生成消息队列的唯一ID,然后使用`msgget()`创建消息队列,并通过`msgctl()`进行操作,如删除队列。接着,通过`msgsnd()`函数发送消息到消息队列,使用`msgrcv()`函数从队列中接收消息。文章提供了详细的函数原型、参数说明及示例代码,帮助读者理解和应用消息队列进行进程间通信。
|
2月前
|
缓存 Linux C语言
C语言 多进程编程(六)共享内存
本文介绍了Linux系统下的多进程通信机制——共享内存的使用方法。首先详细讲解了如何通过`shmget()`函数创建共享内存,并提供了示例代码。接着介绍了如何利用`shmctl()`函数删除共享内存。随后,文章解释了共享内存映射的概念及其实现方法,包括使用`shmat()`函数进行映射以及使用`shmdt()`函数解除映射,并给出了相应的示例代码。最后,展示了如何在共享内存中读写数据的具体操作流程。
|
2月前
|
消息中间件 Unix Linux
C语言 多进程编程(二)管道
本文详细介绍了Linux下的进程间通信(IPC),重点讨论了管道通信机制。首先,文章概述了进程间通信的基本概念及重要性,并列举了几种常见的IPC方式。接着深入探讨了管道通信,包括无名管道(匿名管道)和有名管道(命名管道)。无名管道主要用于父子进程间的单向通信,有名管道则可用于任意进程间的通信。文中提供了丰富的示例代码,展示了如何使用`pipe()`和`mkfifo()`函数创建管道,并通过实例演示了如何利用管道进行进程间的消息传递。此外,还分析了管道的特点、优缺点以及如何通过`errno`判断管道是否存在,帮助读者更好地理解和应用管道通信技术。
|
2月前
|
Linux C语言
C语言 多进程编程(七)信号量
本文档详细介绍了进程间通信中的信号量机制。首先解释了资源竞争、临界资源和临界区的概念,并重点阐述了信号量如何解决这些问题。信号量作为一种协调共享资源访问的机制,包括互斥和同步两方面。文档还详细描述了无名信号量的初始化、等待、释放及销毁等操作,并提供了相应的 C 语言示例代码。此外,还介绍了如何创建信号量集合、初始化信号量以及信号量的操作方法。最后,通过实际示例展示了信号量在进程互斥和同步中的应用,包括如何使用信号量避免资源竞争,并实现了父子进程间的同步输出。附带的 `sem.h` 和 `sem.c` 文件提供了信号量操作的具体实现。
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
34 3
|
8天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
25 6
|
28天前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
35 10