c语言每日一练(9)
前言:
每日一练系列,每一期都包含5道选择题,2道编程题,博主会尽可能详细地进行讲解,令初学者也能听的清晰。每日一练系列会持续更新,暑假时三天之内必有一更,到了开学之后,将看学业情况更新。
五道选择题:
1、以下 scanf 函数调用选项中, 错误的是( )
struct T
{
char name[20];
int age;
int sex;
} a[5], *pa=a;
A、scanf("%s",a[0].name);
B、scanf("%d", &pa[0].age);
C、scanf("%d",&(pa->age));
D、scanf("%d", pa->age);
解析:首先,你要明白scanf需要什么,它需要地址,你只要给它对应数据的地址,它就会根据地址对你所给的目标进行修改。
选项A,通过结构体数组访问到结构体,再通过结构体访问到结构体成员,但它访问的是字符数组,而字符数组的本质就是指针,故A正确。选项B,使用结构体数组的方式访问结构体,再通过结构体访问结构体成员,不同于A的是它访问的是整型变量,整型变量没有字符数组那么特殊,因此要取地址,它也取了,故B正确。
选项C,使用->的方式取到了结构体成员,并取了地址,和B雷同,C正确。D选项,与C不同的就在于没有取地址,因此,scanf无法正确地执行,故D错误。
2、关于指针下列说法正确的是【多选】( )
A、 任何指针都可以转化为void * B、 void *可以转化为任何指针
C、 指针的大小为8个字节 D、 指针虽然高效、灵活但可能不安全
解析:C错误,因为指针的大小是随着平台的变化而变化的,当指针处于32位平台时,大小为4,为64位平台时位8,ABD没有问题。
3、请指出以下程序的错误【多选】( )
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
解析:代码1错误,因为得同时满足两个条件才会直接报错,但很显然,我们的目的是令num>0,p!=NULL,因此一个有误就得报错。
在语句GetMemory(&str,100);中传入str的地址,在语句char*str=NULL;中str初始化为空指针,但是str指针变量也有地址,所以参数char**p里面的p保存的是指针变量str的地址,所以调用GetMemory函数之后,动态开辟的空间的地址存放在了str中,在函数返回之后没有释放内存,但是这不会导致程序错误,只会导致内存泄漏。故代码2无误。
代码3错误,&str相当于是对地址的地址进行操作了,没操作到该操作的。代码4是正确的,相当于printf("hello");综上所述,选AC
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、 内存泄露
解析:选项A,观察代码可以看出创建的数组大小为255,因此,数组下标最大为244,i<=MAX的条件一定会令i达到255,会越界。选项B,每次循环i++,MAX的值是定值,好像不会造成死循环,但i是unsigned char型的,因此,i最大为255,当要超出255时就会像一个圆绕回到0,所以会导致死循环。
C选项,创建的临时变量,在栈中,应该会由系统自动释放,所以是不存在内存泄漏的问题。栈溢出:属于缓冲区溢出的一种。栈溢出是由于C语言系列没有内置检查机制来确保复制到缓冲区的数据不得大于缓冲区的大小,因此当这个数据足够大的时候,将会溢出缓冲区的范围,D选项,无稽之谈,我都没有申请空间,所以根本不会有内存泄漏。综上所述,答案为AB
5、请问下列程序的输出是多少( )
#include<stdio.h>
int main()
{
unsigned char i = 7;
int j = 0;
for (; i > 0; i -= 3)
{
++j;
}
printf("%dn", j);
return 0;
}
A、2 B、死循环 C、173 D、172
解析:unsigned char 型的范围为0~255,为负数的时候也会像圆一样绕回来,反着绕。观察代码,i被初始化为7,每次进行循环i-3,i>0循环继续,每次循环j++,最后打印出j,目标计算循环次数。i=7,循环到i=-2时,由于unsigned char的特殊性会令i=254,254/3=84余2,即i=2,再使i=-1,由于特殊性,i=255,255/3=85,i=0,循环结束。综上所述,循环次数为3+84+1+85=173,故选C
编程题1:
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
思路:猜中次数很好计算,一次循环就可以计算出来,难的是伪猜中的次数。首先,猜中不能被算作伪猜中,那么一旦猜中,那两个被猜中的槽就可以看作配对成功,不用再考虑,可以把它们置为-1。在后期的判定中,一遇到-1便continue切换槽位即可,而一旦伪猜中成功,那两个槽也相当于废掉了,不能在同一个槽伪猜中多次,这是一个隐藏规则,所以把这两个槽也置为-1
#include<stdio.h>
#include<stdlib.h>
int* masterMind(char* solution, char* guess, int* returnSize) {
*returnSize = 2;
//初始化返回的数组,因为我们仅仅只需要返回猜中次数和伪猜中次数,所以必定为2
int* order = (int*)malloc(sizeof(int) * 2);
//创建返回数组
int i = 0; int j = 0;
int count_true = 0;//猜中次数计数
int count_false = 0;//伪猜中次数计数
for (i = 0; i < 4; i++)
//一共四个槽,所以solution和guess的数组大小都为4
{
if (solution[i] == guess[i])
{
count_true++;
solution[i] = -1;
guess[i] = -1;
//由于猜中的槽,伪猜中的不能重复,所以置为-1,用来判定
}
}
for (i = 0; i < 4; i++)
{
if (solution[i] == -1)
{
continue;
}
for (j = 0; j < 4; j++)
{
if (guess[j] == -1)
{
continue;
}
if (solution[i] == guess[j])
{
count_false++;
solution[i] = -1;
guess[j] = -1;
}
}
}
order[0] = count_true;
//存放猜中次数
order[1] = count_false;
//存放伪猜中次数
return order;
//返回目标
}
编程题2:
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
思路:暴力破解,没什么好说的,两个循环遍历完蛋
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
*returnSize = 2;
//只用返回两个数,所以数组大小必定为2
int* order = (int*)malloc(sizeof(int) * 2);
//创建一个符合条件的数组
int i = 0; int j = 0;
for (i = 0; i < numsSize; i++)
{
for(j=i+1;j<numsSize;j++)
{ //减少循环次数
if (nums[i] + nums[j] == target)
//找到目标,直接储存并返回
{
order[0] = i;
order[1] = j;
return order;
}
}
}
return NULL;//找不到返回空
}
好了,今天的练习到这里就结束了,感谢各位友友的来访,祝各位友友前程似锦O(∩_∩)O