c语言基础练习题1(牛客网)

1、下面程序段的运行结果是()

1

2

3

4

int x, y;

x = y = 0;

while (x < 15) y++, x += ++y;

printf("%d,%d", y, x);

A 、20,7

B、6,12

C、20,8

D、8,20

答案:D

解析:本题主要是分为两个语句来看,首先是y++,然后是x += ++y,这样一说这个题就变得很清楚了,第一次x=2,y=2;第二次x=6,y=4;第三次x=12,y=6;第四次x=20,y=8

2、下列程序的功能是将 s 中的字符串按长度由小到大排列,请为横线处选择合适的程序()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

#include <stdio.h>

#include <string.h>

void f(char *p[], int n) {

    char *t;

    int i, j;

    for (i = 0; i < n - 1; i++)

        for (j = i + 1; j < n; j++)

            if (strlen(*(p + i)) > strlen(*(p + j))) {

                t = *(p + i);

                *(p + i) = *(p + j);

                *(p + j) = t;

            }

}

int main() {

    char *s[] = {"abc""abcdef""abbd"};

    f(s, 3);

    for (int i = 0; i < 3; i++)

        printf("%s\n", ____);

    return 0;

}

A、s+i

B、s[i]

C、*s[i]

D、&s[i]

答案:B

解析:该题主要考察指针数组的遍历,因此直接看主函数部分即可;这是一个指针数组,数组中的每一个元素都是一个指向字符(实际上是字符串字面量的首字符)的指针。

A选项:s是数组名,代表数组首元素的内存位置(但不是一个可以修改的左值),在大多数表达式中s会被隐式转换为char**(指向字符指针的指针),指向数组的首元素(即s[0]),因此它+i并不能遍历数组。

B选项:s[i]是数组s中第i个元素的值,类型是char*(字符指针),指向第i个字符串的首字符,通过它可以遍历数组

C选项:s[i]是指向第i个字符串的首字符,再加*得到的就是该字符串的第一个字符,而不是整个字符串

D选项:s[i]本身是指向字符指针的一个指针,对它取地址得到的是这个指针的地址,并不是这个字符串

指针数组的类型本质上是一个二级指针类型

3、参考以下代码,在大端字节机器中x.c的值为

1

2

3

4

union A {

    short c;

    char buf[4];

} x = {0x01, 0x02, 0x03, 0x04}

A、0x102

B、0x201

C、0x304

D、0x403

答案:A

解析:首先我们看到题目说的是大端字节机器,在大端字节机器中数据的高位字节存放在内存的低地址处,而低位字节则存放在高地址处,如下图所示:

       在大端机器中,数据的读取是从低位地址开始,即内存的低地址处开始的,但存储时高位字节存放在低地址,因此在我们输出x.c的时候因为是short所以只会读取2个字节所以从低地址开始读取读到的就是0x01和0x02,省略第一个0得到的就是0x102;

       在小端机器中,数据的存储如图右,如果还是同样读取2个字节,则读取到的就是0x04和0x03,我在我自己的小端机器上将一个int强转为2个字节的short输出得到的结果是0x304,

这跟0x04 0x03不同,原因是我使用的是十六进制输出,尽管在小端机器上低位字节首先存储,但在打印时,十六进制数仍然按照高位在前、低位在后的方式显示(这是十六进制数的标准表示方式)。

4、则以下程序段的执行结果是( )

1

2

3

4

char ch = 'a';

int k = 12;

printf("%x,%o,", ch, ch, k);

printf("k=%%d\n",k);

A、因变量类型与格式描述符的类型不匹配,输出无定值

B、输出项与格式描述符个数不符,输出为零值或不定值

C、61,141,k=%d

D、61,141,k=%12

答案:C

解析:本题主要考察输出,我们直接看第一个printf,首先注意双引号,双引号里面只有%x和%,但是后面却有三个参数,这就会导致参数k被忽略,只会输出ch的十六进制和八进制结果;我们再来看第二个printf,%是控制符,%%会输出一个%,而d就会原样输出,k的值也不会被输出,要想输出选项D中的k=%12,我们的第二个输出语句就应该改为printf("k=%%%d\n",k);,这样才能以%d来打印k的值。

5、在C程序中,可把整型数以二进制形式存放到文件中的函数是()

A、fprintf函数

B、fread函数

C、fwrite函数

D、fputc函数

答案:C

解析:fprintf函数:这个函数用于将格式化的数据写入文件,它通常用于文本文件的写入,而不是二进制文件。就是将数据按照指定的格式写入,数据可以是可以是整数、浮点数、字符、字符串等;

fread函数:这个函数用于从文件中读取数据,因此不适用于将数据写入文件;

fwrite函数:这个函数用于将内存中的数据块(包括整型数)以二进制形式写入文件;

fputc函数:这个函数用于将单个字符写入文件,不适用于写入整型数,特别是以二进制形式。

6、下面的代码输出是() 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

int main() {

    union Data {

        struct {

            int x;

            int y;

        } s;

        int x;

        int y;

    } d;

    d.x = 1;

    d.y = 2;

    d.s.x = d.x * d.x;

    d.s.y = d.y + d.y;

    printf("%d %d\n", d.s.x, d.s.y);

    return 0;

}

 A、1 4

B、4 4

C、1 2

D、4 8

答案:D

解析:我们先来分析代码,代码中是一个共用体(联合体)里面嵌套了一个结构体,共用体是用同一片空间地址,因此我们在对共用体里面的x和y赋值的时候,只会保留最后一次的赋值结果,在执行完d.y = 2;这个语句后d.y、d.x和结构体里面的x的值都为2,在执行d.s.x = d.x * d.x;这个语句之后结构体中的x就为4,同时因为结构体在共用体里面,它们共用同一片空间地址,所以此时d.x和d.y的值也变成了4,最后再把结构体里面的y赋值,此时y就为8,故答案为D。

7、以下函数用法正确的个数是:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

void test1(){

    unsigned char array[MAX_CHAR+1],i;

    for(i = 0;i <= MAX_CHAR;i++){

        array[i] = i;

    }

}

char*test2(){

    char p[] = "hello world";

    return p;

}

char *p = test2();

void test3(){

    char str[10];

    str++;

    *str = '0';

}

A、0

B、1

C、2

D、3

答案:A

解析:首先来看第一个函数,定义了一个无符号的字符数组,在这里我们就要考虑到一个范围的问题,无符号的字符型范围是0~255,因此这里的i的范围也就是0~255,故当i++超过256之后就无法表示了,以此第一个函数错误;

第二个函数,定义了一个字符数组,数组名为P,这个函数是一个指针函数,它的返回值是P,而这个P是数组名,函数会将字符串常量的字符逐个复制到p数组里面,返回p则是返回数组p,p是局部变量是在栈区开辟的,在执行完函数之后会被计算机自动释放,它的内部创建的数组,变量等会随着函数体的结束而销毁,P会指向一段无效的空间,因此第二个也不对;

第三个函数,str是一个数组名,在下面对str++是错误的,因为数组名是一个常量,不能修改它的值。

8、设有如下的说明和定义

1

2

3

4

5

6

struct {

    int a;

    char *s;

} x, *p = &x;

x.a = 4;

x.s = "hello";

则以下叙述中正确的是()

A、(p++)->a与p++->a都是合语法的表达式,但二者不等价

B、语句 ++p->a; 的效果是使p增1

C、语句 ++p->a; 的效果是使成员a增1

D、语句 *p->s++; 等价于 (*p)->s++;

答案:C

解析:题目是定义了一个结构体,结构体里面是一个整形变量a和一个字符型的指针,然后定义了这个结构体类型的变量x,指向这个结构体类型的指针p,并且将p初始化指向x;然后对a和s赋值;

首先我们需要清楚的是在c语言中,成员运算符->的优先级高于单目运算符++,接下来看选项,对于A选项,p++是后++,所以会先访问结构体的成员a之后p再自加指向另一个地址,这是合法的,对于第二个p++->a是不合法的,p++是一个右值,它不能作为->的左侧操作数。

B选项:首先会访问结构体的成员a,之后使成员a增1,因此C选项就是正确的

D选项:对于*p->s++,p会先跟->结合,先访问s,这里访问的s是一个指针,现在指针指向的是第一个元素h,将指针s++,则指针会指向第二个元素e,此时再加*,就会取到指针指向的内容,也就是字母e;对于 (*p)->s++;先对p解引用得到x,然后访问x中的成员s,再对指针进行++操作,这样得到的是指向e的指针,是一个地址,所以两者并不等价。

这里提到了左值和右值,那就顺便解释一下:

        左值通常指的是一个具有持久性和位置依赖性的表达式。在C和C++中,左值通常表示一个具体的对象或变量,它们可以在内存中有明确的存储位置,并且可以通过取地址运算符(&)获取其地址。左值最显著的特征是它可以出现在赋值操作的左侧,即可以将另一个值赋给它。这种属性让左值在需要存储和修改数据时成为首选。例如,变量名、数组的元素等都是左值的典型示例。

        右值通常表示一个临时的、不具有持久性和位置依赖性的表达式。右值通常代表的是在表达式计算过程中产生的临时结果,这种结果无需长时间存储,只在表达式计算的瞬间有用。在C和C++中,右值不能出现在赋值操作的左侧,因为它们不具备可修改性。右值也没有明确的内存位置,因此不能通过取地址运算符获取其地址。例如,常量、字面值、临时对象、函数返回的临时结果等都是右值的示例。

  1. 持久性:左值强调长期性和位置的固定,而右值则强调数据的临时性和即刻消失。
  2. 位置依赖性:左值可以具有明确的内存位置,而右值则通常没有。
  3. 赋值操作:左值可以出现在赋值操作的左侧,而右值则不能。
  4. 用途:左值适用于进行修改操作和作为函数参数传递,而右值则适用于一次性计算和资源转移等场景。

9、下列代码输出是()

1

2

3

4

5

6

7

8

9

char *a[] = {"BEIJING""SHENZHEN""SHANGHAI""GUANGZHOU"};

char **pa[] = {a+3, a+2, a+1, a};

char ***ppa = pa;

int main(void) {

    printf("%s, ", **++ppa);

    printf("%s, ", *--*++ppa+3);

    printf("%s, ", *ppa[-2]+3);

    printf("%s", ppa[-1][-1]+1);

}

A、BEIJING, SHENZHEN, SHANGHAI,GUANGZHOU

B、SHANGHAI, JING, NGZHOU, HENZHEN

C、SHANGHAI,BEIJING, GUANGZHOU, SHENZHEN

D、SHANGHAI,EIJING,ZHOU,ZHEN

答案:B

解析:

优先级:++与 * 同优先级,自右向左结合,+的优先级低于它俩

**++ppa:首先ppa与++结合,ppa指向pa[1],*pa[1]得到的是指针a[2],再对a[2]取内容得到的就是SHANGHAI

*--*++ppa+3:在第一个输出中,ppa就指向了pa[1],它再自加,则它指向pa[2],对它取内容就得到指向a[1]的指针,然后这个指针自减1,则此得到的是指向a[0]的指针,再取内容就得到了指向BEIJING的指针a[0],此时这个指针指向的是首字母B,然后+3,此时指针指向第四个字母J,然后进行打印出的结果就为JING;

*ppa[-2]+3:在这里ppa[-2]就相当于*(ppa-2),在前面两个输出执行之后,现在ppa指向的是pa[2],现在-2之后指针指向pa[0],但是此时ppa本身指向pa[2],pa[0]又指向a[3],现在又取内容*ppa[-2],这时得到的是一个指向字符串GUANGZHOU的指针,这个指针指向首字母G,然后再+3,之后指针指向的是字母N,这时候打印出来的就是NGZHOU;

ppa[-1][-1]+1:首先ppa[-1][-1]等价于*(*(ppa-1)-1),ppa指向的是pa[2],先进行-1,这时候ppa指向pa[1],然后*pa[1],得到的是指向a[2]的指针,这个指针再-1,减一之后这个指针指向a[1],然后*a[1],得到的是指向字符串SHENZHEN的指针,这个指针指向首字母S,然后指针+1,这时指针指向第二个字母H,然后打印得到的是HENZHEN。

关键点:本题的关键在于指针++与+n(n为具体数字),的区别,++是指针自加,加完之后指针的指向发生了改变,但是+n之后是指针指向当前位置的后面第n个位置,这时指针本身的指向并没有改变;还有一个是变址符[]和*的互换,例如p[3]可以换成*(p+3)。 

10、有如下所示程序,请问输出的结果为什么? 

1

2

3

4

5

6

7

8

9

#include <stdio.h>

int main(int argc, char *argv[])

{

    int a = 212;

    char *p = (char*)&a;

    printf("%d\n", *p);

   return 0;

}

答案:-44

解析:首先程序定义了一个整形变量并赋值为212,计算机存储这个数需要把它转为二进制存储,212转为二进制为1101 0100,之后因为它是int型变量,计算机会给它开辟四个空间地址,但是由于它没有超过256,因此在第一个地址就能存完,后面三个地址上存的全部都为0;存完之后第二步把它强转为了char类型,char类型之占一个字节,但是由于计算机默认存储的是有符号的数,这时一个字节8位就只能最大存128,最高位为符号位,但是在转之前我们的数已经存到了第一个字节空间地址上,因此在我们强转之后由于存储不下212,因此计算机会把该空间地址上的数的第一位默认为符号位,这时符号位为1,是负数,因此输出我们需要去找它的补码,1101 0100的补码就为1010 1100,转为十进制输出就为-44。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值