国庆练习(Day24)

作业一

数组练习

选择题

1.1、若有定义语句:int a36; ,按在内存中的存放顺序,a 数组的第10个元素是

a04 B) a13 C)a03 D)a14

解析:

从 a00 开始,第一行有 6 个元素,分别是 a00 到 a05,即第 1 到第 6 个元素。

接着从 a10 开始,第二行前 4 个元素是 a10 到 a13,即第 7 到第 10 个元素。

所以,第 10 个元素是 a13

解答:

B

1.2、有数组 int a5 = {10,20,30,40,50}, 以下表达式编译错误是____________。

A) a ++ ;

B) a5 = 20 ;

C) a + 20 ;

D) (a-3, a3) ;

解析:

A) a++ ;

错误:a++ 是不合法的。

原因:在 C 语言中,数组名 a 是一个指向数组第一个元素的指针常量,它的值不可改变。也就是说,数组名 a 不能被自增,因为它是一个 常量指针,指向数组首地址,不能通过 ++ 操作改变。

B) a5 = 20 ;

错误:虽然语法上没有问题,但会导致 数组越界 错误。

原因:a5 实际上是访问数组的第 6 个元素,而 a5 数组只有 5 个元素,索引范围是 a0 到 a4。因此,访问 a5 会导致 越界访问,尽管某些编译器可能不会报错,但这是一个逻辑错误。

C) a + 20 ;

正确:这个表达式不会编译错误。

原因:a + 20 是一个合法的指针运算。它将指针 a 偏移 20 个元素的位置,虽然这样做的结果可能是非法的地址访问,但仅仅是表达式本身不会导致编译错误。

D) (a-3, a3) ;

正确:这个表达式不会编译错误。

原因:这是一个逗号表达式,先计算 a-3(虽然结果无实际意义),然后计算 a3,最终返回 a3 的值。语法上没有问题。

解答:

A

1.3、以下错误的定义语句是 _______

A)int x\[\]3 = {{0},{1},{1,2,3}};

B)int x43 = {{1,2,3},{1,2,3},{1,2,3},{1,2,3}};

C)int x4\[\] = {{1,2,3},{1,2,3},{1,2,3},{1,2,3}};

D)int x\[\]3 = {1,2,3,4};

解析:

A) int x\[\]3 = {{0}, {1}, {1, 2, 3}};

正确:这是合法的定义。

原因:二维数组在定义时,必须指定列的大小(本例中的 3)。行数可以省略,编译器会根据初始化的内容推断行数。每行的元素少于 3 时,未指定的元素会自动填充为 0。因此,这个定义是合法的。

B) int x43 = {{1,2,3},{1,2,3},{1,2,3},{1,2,3}};

正确:这是合法的定义。

原因:明确定义了 4 行 3 列的二维数组,并且每行都初始化了 3 个元素,符合数组初始化规则。

C) int x4\[\] = {{1,2,3},{1,2,3},{1,2,3},{1,2,3}};

错误:这是非法的定义。

原因:在声明二维数组时,列的大小必须明确指定,但这个语句没有为列指定大小(即 \[\] 是空的)。编译器无法推断每行有多少个元素,因此会报错。

D) int x\[\]3 = {1, 2, 3, 4};

正确:这是合法的定义。

原因:这是二维数组的另一种初始化方式。虽然看起来像是一维数组的初始化,但编译器会将 1, 2, 3, 4 填充到 3 列的二维数组中。结果是 x00 = 1, x01 = 2, x02 = 3, x10 = 4,其余的未初始化元素将被自动填充为 0。因此,这个定义也是合法的。

解答:

C

1.4、 int i,x33={1,2,3,4,5,6,7,8,9}; 则下面语句

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

   printf(″%d, ″,xi2-i);

的输出结果是

A)1, 4, 7 B)1, 5, 9 C)3, 6, 9 D)3, 5, 7

解析:

这里 xi2-i 表示:

当 i = 0 时,x02-0 = x02 = 3

当 i = 1 时,x12-1 = x11 = 5

当 i = 2 时,x22-2 = x20 = 7

解答:

D

1.5、表达式" sizeof(int 12)/sizeof(int) "的值为 _____

A ) 2 B ) 3 C ) 4 D ) 5

解析:

sizeof(int 12):

这个数组包含 1 行 2 列,总共有 1 × 2 = 2 个 int 元素。

每个 int 占 4 字节,因此整个数组的大小为 2 × 4 = 8 字节。

sizeof(int):

这是单个 int 类型的大小,在大多数系统上为 4 字节。

解答:

A

1.6有以下程序

#include main()

{ char s\[\]="012xy\07s34f4w2";

int i,n=0;

for(i=0;si!=0;i++)

if(si>='0'&&si<='9')

n++;

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

}

程序运行后的输出结果是____________

A)0 B)3 C)7 D)8

解析:

字符数组 s\[\] 的内容为 "012xy\07s34f4w2":

"012xy\07s34f4w2" 是一个字符串常量。

\07 是一个八进制转义字符,对应的值是 7。

这个字符串的实际内容是:"012xy\x07s34f4w2",它的长度是 14 个字符(包括 \07)。

但在这个程序中,八进制字符不会影响字符串的解析,它仅仅是作为一个不可见的字符。

for 循环 遍历整个字符串,直到遇到空字符 '\0' 为止。

在 if (si >= '0' && si <= '9') 中,检查当前字符是否为数字字符 '0' 到 '9'。如果是数字字符,则计数器 n 增加。

字符串 "012xy\07s34f4w2" 中的数字字符为:

'0', '1', '2', '3', '4', '4', '2'

一共 7 个数字字符。

解答:

C

1.7、有以下程序

#include <stdio.h>

main( )

{ char s ="wstuv"; printf("%c\n",*s+2);

}

程序运行后的输出结果是

A)t B) tuv C)y D)出错

解析:

s 是一个字符数组,数组名 s 是指向第一个元素的指针。

*s 解引用 s,表示数组的第一个元素 s0,即字符 'w'。

表达式 *s + 2:

*s 取的是 s0,即字符 'w'。

'w' 在 ASCII 码中的值是 119。

*s + 2 相当于 119 + 2 = 121,ASCII 码值 121 对应的字符是 'y'。

printf("%c\n", *s + 2); 输出的就是字符 'y'。

解答:

C

1.8 数组 int a5 = {10, 20, 30, 40,50}, 有以下语句,其输出_______

printf("%d\n", *(&a +1) );

A) 20 B) 30 C) 随机值 D)编译报错

解析:

&a 的含义:

&a 是 数组 a 的地址,它的类型是 int (*)5,即指向一个大小为 5 的整型数组的指针。

注意,这与 a 的地址(指向数组第一个元素 a0 的地址)是不同的。a 作为数组名时相当于 &a0,是一个指向第一个元素的指针,而 &a 是整个数组的地址。

&a + 1 的含义:

&a + 1:这个表达式实际上是将 &a (数组 a 的地址)偏移一个数组的大小。因为 &a 是一个指向整个数组的指针,偏移 1 意味着它指向了数组 a 之后的地址。

也就是说,&a + 1 实际上指向的是数组 a5 后面的内存位置。

*( &a + 1 ) 的含义:

*( &a + 1 ) 试图 解引用 偏移后的地址。由于 &a + 1 指向数组 a 之外的内存,这意味着该表达式取出的值是数组 a 之后的内存中的内容。

这里访问的是超出数组范围的内存空间,会导致未定义行为。因此,输出的值是 随机的,也就是不可预测的。

解答:

C

1.9 有以下程序

include <stdio.h>

int main()

{ int s12={1,2,3,4,4,3,2,1,1,1,2,3}, c5={0,0,0,0,0}, i ;

for(i=0;i<12;i++) cs\[i]++ ;

for(i=1;i<5;i++) printf("%d,",ci); printf("\n");

}

A) 4 ,3, 3, 2 B) 2 , 3, 4, 4

C) 1, 2, 3 ,4 D ) 4, 4, 2 ,3

解析:

数组 s12 的初始化为:{1, 2, 3, 4, 4, 3, 2, 1, 1, 1, 2, 3}。

这个数组包含 12 个元素。

数组 c5 的初始化为:{0, 0, 0, 0, 0}。

这是一个用于统计出现次数的数组,ci 表示整数 i 在数组 s 中出现的次数。

for 循环统计元素出现次数:

cs\[i]++ 根据数组 si 的值,更新数组 c\[\] 的对应索引。

这意味着,数组 c 会记录数组 s 中数字 1 到 4 的出现次数。

数组 s 中每个数字的出现次数:

数字 1 出现了 4 次。

数字 2 出现了 3 次。

数字 3 出现了 3 次。

数字 4 出现了 2 次。

因此,数组 c 更新为:{0, 4, 3, 3, 2}。

输出部分:

for (i = 1; i < 5; i++) printf("%d,", ci);

该循环会打印数组 c1 到 c4 的值,也就是 4, 3, 3, 2。

解答:

A

1.10 有数组 int a34 = {10,20,30,40,50,60,70,80,90,100,110,120},执行以下语句输出的是_______________

printf("%d\n", *(*a+2) + 3 );

A) 语句有错 B) 120 C) 30 D) 33

解析:

*a:

a 是一个二维数组,*a 代表 指向第一行的指针,也就是 a0,即地址 &a00,指向的是第一个元素 10。

*a + 2:

*a 是 a0 的首地址,即 &a00,加上 2 就是指向 a02,也就是 30 的地址。

*(*a + 2):

这是对 a02 解引用,结果是 30。

*(*a + 2) + 3:

这一步是在 30 的基础上再加上 3,所以结果是 30 + 3 = 33

解答:

D

2、填空题

2.1、有以下程序

#include <stdio.h>

main( )

{ int i,n ={0,0,0,0,0};

for(i=1;i<=4;i++)

{ni=ni-1*3+1;

printf("%d",ni);}

}

程序运行后输出结果是 __________

解析:

当 i = 1:

n1 = n0 * 3 + 1 = 0 * 3 + 1 = 1

输出:1

当 i = 2:

n2 = n1 * 3 + 1 = 1 * 3 + 1 = 4

输出:4

当 i = 3:

n3 = n2 * 3 + 1 = 4 * 3 + 1 = 13

输出:13

当 i = 4:

n4 = n3 * 3 + 1 = 13 * 3 + 1 = 40

输出:40

解答:

141340

2.2、执行以下程序的输出结果是_.

#include <stdio.h>

int main()

{ int i,n4={1,0,0,0};

for(i=1;i<=3;i++)

{ ni=ni-1*2+1; printf("%d",ni); }

}

解析:

当 i = 1:

n1 = n0 * 2 + 1 = 1 * 2 + 1 = 3

输出:3

当 i = 2:

n2 = n1 * 2 + 1 = 3 * 2 + 1 = 7

输出:7

当 i = 3:

n3 = n2 * 2 + 1 = 7 * 2 + 1 = 15

输出:15

解答:

3715

2.3、下面程序运行的结果为_________。

main()

{

int x5,i;

x0 = 1;x1 = 2;

for(i = 2;i<5;i++) xi = xi-1 + xi-2;

for(i = 2;i<5;i++) printf("%d",xi);

}

解析:

i = 2:

x2 = x1 + x0 = 2 + 1 = 3

当 i = 3:

x3 = x2 + x1 = 3 + 2 = 5

当 i = 4:

x4 = x3 + x2 = 5 + 3 = 8

数组 x 的最终内容:

x0 = 1

x1 = 2

x2 = 3

x3 = 5

x4 = 8

第二 for 循环:

再次循环从 i = 2 到 i < 5,输出 x2, x3, x4 的值。

输出:3, 5, 8

解答:

358

2.4、有以下程序

#include <sthio.h>

int main()

{

int arr\[\] = {1,3,5,7,2,4,6,8}, i, start ;

scanf("%d", &start);

for(i=0,i<7,i+=2)

printf("%d",arr(start+i)%5);

}

若在程序运行时输入整数 10 < 回车**>**,则输出结果为_______

解析:

当 i = 0:

arr(start + i) % 5 = arr(10 + 0) % 5 = arr10 % 5 = arr0

输出:1

当 i = 2:

arr(start + i) % 5 = arr(10 + 2) % 5 = arr12 % 5 = arr2

输出:5

当 i = 4:

arr(start + i) % 5 = arr(10 + 4) % 5 = arr14 % 5 = arr4

输出:2

当 i = 6:

arr(start + i) % 5 = arr(10 + 6) % 5 = arr16 % 5 = arr1

输出:3

解答:

1523

2.5下面程序运行的结果为_________。

#include "stdio.h"

main()

{ int i,j,a\[\]={0,2,8,4,5};

printf("\n");

for(i=1;i<=5;i++)

{ j=5-i;

printf("%2d",aj);

}

}

解析:

当 i = 1:

j = 5 - 1 = 4

输出 a4 = 5。

当 i = 2:

j = 5 - 2 = 3

输出 a3 = 4。

当 i = 3:

j = 5 - 3 = 2

输出 a2 = 8。

当 i = 4:

j = 5 - 4 = 1

输出 a1 = 2。

当 i = 5:

j = 5 - 5 = 0

输出 a0 = 0。

解答:

5 4 8 2 0

2.6有以下程序

#include <stdio.h>

int main()

{ int n2,i,j;

for(i=0;i<2;i++) ni=0; for(i=0;i<2;i++)

for(j=0;j<2;j++) nj=ni+1;

printf("%d\n",n1);

}

程序运行后的输出结果是 【】

解析:

第一次for循环作用是对数组进行初始化全部赋值为0

第二个双层for循环外层是控制次数

第一次i=0时

j=0

n0=n0+1=0+1=1

j=1

n1=n0+1=1+1=2

第二次i=1时

j=0

n0=n1+1=2+1=3

j=1

n1=n1+1=2+1=3

输出n1为3

解答:

3

3、编程题

3.1、 一个班10个学生的成绩,存放在一个一维数组中,要求找出其中成绩最高的学生的成绩和该生的序号。试编程。(试着用下标法和地址法两种方法表示数组)
代码解答:

下标法:

cpp 复制代码
#include <stdio.h>

int main() {
    int scores[10] = {85, 92, 78, 90, 88, 95, 82, 80, 91, 89}; // 假设的成绩
    int maxScore = scores[0]; // 假设第一个学生成绩为最高分
    int maxIndex = 0; // 最高分的序号(下标)

    // 找到最高分和对应的序号
    for (int i = 1; i < 10; i++) {
        if (scores[i] > maxScore) {
            maxScore = scores[i]; // 更新最高分
            maxIndex = i; // 更新最高分序号
        }
    }

    // 输出结果
    printf("最高成绩: %d\n", maxScore);
    printf("该生的序号: %d\n", maxIndex + 1); // 序号从 1 开始

    return 0;
}

地址法:

cpp 复制代码
#include <stdio.h>

int main() {
    int scores[10] = {85, 92, 78, 90, 88, 95, 82, 80, 91, 89}; // 假设的成绩
    int maxScore = *scores; // 假设第一个学生成绩为最高分
    int maxIndex = 0; // 最高分的序号(下标)

    // 找到最高分和对应的序号
    for (int i = 1; i < 10; i++) {
        if (*(scores + i) > maxScore) {
            maxScore = *(scores + i); // 更新最高分
            maxIndex = i; // 更新最高分序号
        }
    }

    // 输出结果
    printf("最高成绩: %d\n", maxScore);
    printf("该生的序号: %d\n", maxIndex + 1); // 序号从 1 开始

    return 0;
}
3.2、有5个学生上4门课程,要求输入全部学生的各门课程成绩,然后输出各门课程的平均成绩,并按照各个学生的平均成绩排序(成绩最高的学生排在数组最前面,最低学生排在数组最后面的行) (试着用下标法和地址法两种方法表示数组)。
代码解答:

下标法:

cpp 复制代码
#include <stdio.h>

#define STUDENTS 5
#define SUBJECTS 4

int main() {
    int scores[STUDENTS][SUBJECTS]; // 存储学生成绩
    float avgScores[STUDENTS]; // 存储每个学生的平均成绩
    float subjectAverages[SUBJECTS] = {0}; // 存储每门课程的平均成绩

    // 输入学生的成绩
    for (int i = 0; i < STUDENTS; i++) {
        printf("输入第 %d 个学生的4门课程成绩:\n", i + 1);
        for (int j = 0; j < SUBJECTS; j++) {
            printf("课程 %d: ", j + 1);
            scanf("%d", &scores[i][j]);
        }
    }

    // 计算每个学生的平均成绩
    for (int i = 0; i < STUDENTS; i++) {
        float total = 0;
        for (int j = 0; j < SUBJECTS; j++) {
            total += scores[i][j];
        }
        avgScores[i] = total / SUBJECTS;
    }

    // 计算每门课程的平均成绩
    for (int j = 0; j < SUBJECTS; j++) {
        float total = 0;
        for (int i = 0; i < STUDENTS; i++) {
            total += scores[i][j];
        }
        subjectAverages[j] = total / STUDENTS;
    }

    // 按照学生的平均成绩排序(简单选择排序)
    for (int i = 0; i < STUDENTS - 1; i++) {
        for (int j = i + 1; j < STUDENTS; j++) {
            if (avgScores[i] < avgScores[j]) {
                // 交换平均成绩
                float temp = avgScores[i];
                avgScores[i] = avgScores[j];
                avgScores[j] = temp;

                // 同时交换对应的成绩
                for (int k = 0; k < SUBJECTS; k++) {
                    int tempScore = scores[i][k];
                    scores[i][k] = scores[j][k];
                    scores[j][k] = tempScore;
                }
            }
        }
    }

    // 输出每门课程的平均成绩
    printf("\n各门课程的平均成绩:\n");
    for (int j = 0; j < SUBJECTS; j++) {
        printf("课程 %d: %.2f\n", j + 1, subjectAverages[j]);
    }

    // 输出每个学生的成绩和平均成绩
    printf("\n学生的成绩及平均成绩:\n");
    for (int i = 0; i < STUDENTS; i++) {
        printf("第 %d 个学生成绩: ", i + 1);
        for (int j = 0; j < SUBJECTS; j++) {
            printf("%d ", scores[i][j]);
        }
        printf(" | 平均成绩: %.2f\n", avgScores[i]);
    }

    return 0;
}

地址法:

cpp 复制代码
#include <stdio.h>

#define STUDENTS 5
#define SUBJECTS 4

int main() {
    int scores[STUDENTS][SUBJECTS]; // 存储学生成绩
    float avgScores[STUDENTS]; // 存储每个学生的平均成绩
    float subjectAverages[SUBJECTS] = {0}; // 存储每门课程的平均成绩

    // 输入学生的成绩
    for (int i = 0; i < STUDENTS; i++) {
        printf("输入第 %d 个学生的4门课程成绩:\n", i + 1);
        for (int j = 0; j < SUBJECTS; j++) {
            printf("课程 %d: ", j + 1);
            scanf("%d", (*(scores + i) + j)); // 地址法输入
        }
    }

    // 计算每个学生的平均成绩
    for (int i = 0; i < STUDENTS; i++) {
        float total = 0;
        for (int j = 0; j < SUBJECTS; j++) {
            total += *(*(scores + i) + j); // 地址法计算
        }
        avgScores[i] = total / SUBJECTS;
    }

    // 计算每门课程的平均成绩
    for (int j = 0; j < SUBJECTS; j++) {
        float total = 0;
        for (int i = 0; i < STUDENTS; i++) {
            total += *(*(scores + i) + j); // 地址法计算
        }
        subjectAverages[j] = total / STUDENTS;
    }

    // 按照学生的平均成绩排序(简单选择排序)
    for (int i = 0; i < STUDENTS - 1; i++) {
        for (int j = i + 1; j < STUDENTS; j++) {
            if (avgScores[i] < avgScores[j]) {
                // 交换平均成绩
                float temp = avgScores[i];
                avgScores[i] = avgScores[j];
                avgScores[j] = temp;

                // 同时交换对应的成绩
                for (int k = 0; k < SUBJECTS; k++) {
                    int tempScore = *(*(scores + i) + k);
                    *(*(scores + i) + k) = *(*(scores + j) + k);
                    *(*(scores + j) + k) = tempScore;
                }
            }
        }
    }

    // 输出每门课程的平均成绩
    printf("\n各门课程的平均成绩:\n");
    for (int j = 0; j < SUBJECTS; j++) {
        printf("课程 %d: %.2f\n", j + 1, subjectAverages[j]);
    }

    // 输出每个学生的成绩和平均成绩
    printf("\n学生的成绩及平均成绩:\n");
    for (int i = 0; i < STUDENTS; i++) {
        printf("第 %d 个学生成绩: ", i + 1);
        for (int j = 0; j < SUBJECTS; j++) {
            printf("%d ", *(*(scores + i) + j)); // 地址法输出
        }
        printf(" | 平均成绩: %.2f\n", avgScores[i]);
    }

    return 0;
}

作业二

指针练习

选择题

1.1、若有下面的变量定义,以下语句中合法的是( )。

int i,a10,*p;

A) p=a+2; B) p=a5;

C) p=a2+2; D) p=&(i+2);

解析:

A) p = a + 2;

这是合法的。a 是一个整型数组,a + 2 表示指向数组中第 3 个元素(索引为 2)的指针。p 可以正确地指向这个元素。

B) p = a5;

这是不合法的。a5 表示数组中第 6 个元素的值(类型为 int),而 p 是一个整型指针,不能直接赋值一个 int 值。

C) p = a2 + 2;

这是不合法的。a2 是数组中第 3 个元素的值(类型为 int),而 p 是指针,不能直接将一个 int 值加 2 后赋值给 p。

D) p = &(i + 2);

这是不合法的。&(i + 2) 表示 i + 2 的地址,但是 i + 2 是一个临时计算的值,不能取得地址。

解答:

A

1.2、有以下程序

main()

{

int a33,*p,i;

p=&a00;

for(i=0;i<9;i++)

pi=i;

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

printf("%d ",a1i);

}

程序运行后的输出结果是 ____________

A)0 1 2

B)1 2 3

C)2 3 4

D)3 4 5

解析:

a00 = 0

a01 = 1

a02 = 2

a10 = 3

a11 = 4

a12 = 5

a20 = 6

a21 = 7

a22 = 8

这里输出的是数组 a 的第二行,即 a10、a11 和 a12,对应的值是 3、4 和 5。

解答:

D

1.3、有以下程序

int main()

{ int a32={0}, (*ptr)2,i,j;

for(i=0;i<2;i++)

{ ptr=a+i;

scanf("%d",*ptr);

*ptr++;

}

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

{

for(j=0;j<2;j++)

printf("%2d",aij);

printf("\n");

}

}

若运行时输入:1 2 3<回车>,则输出结果为 ___________

A)产生错误信息

B)1 0

2 0

0 0

C)1 2

3 0

0 0

D)1 0

2 0

3 0

解析:

用户输入 1 2 3(中间用空格分隔),这样在循环中会被逐个读取:

当 i = 0 时,输入 1,将其存储到 a00

当 i = 1 时,输入 2,将其存储到 a10

因为循环只运行了 2 次,所以 a2 不会被修改。

对于 i = 0,a0 = {1, 0} 输出 1 0

对于 i = 1,a1 = {2, 0} 输出 2 0

对于 i = 2,a2 = {0, 0} 输出 0 0

解答:

C

1.4、有以下程序

main()

{ int a\[\]={1,2,3,4,5,6,7,8,9,0},*p;

for(p=a;p<a+10;p++)

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

}

程序运行后的输出结果是 __________

A)1,2,3,4,5,6,7,8,9,0,

B)2,3,4,5,6,7,8,9,10,1,

C)0,1,2,3,4,5,6,7,8,9,

D)1,1,1,1,1,1,1,1,1,,1,

解析:

p = a 将指针 p 初始化为数组 a 的首地址。

p < a + 10 是循环的条件,表示只要 p 小于数组 a 的末尾地址(即 a 的第 10 个元素的地址),循环将继续执行。

*p 表示获取 p 指向的当前元素的值,并将其打印。

在循环中,指针 p 将依次指向数组 a 中的每个元素,输出顺序为:

第一次循环:*p 是 1

第二次循环:*p 是 2

第三次循环:*p 是 3

第四次循环:*p 是 4

第五次循环:*p 是 5

第六次循环:*p 是 6

第七次循环:*p 是 7

第八次循环:*p 是 8

第九次循环:*p 是 9

第十次循环:*p 是 0

解答:

A

1.5、有以下程序

main()

{

char s\[\]="159",*p;

p=s;

printf("%c",*p++);

printf("%c",*p++);

}

程序运行后的输出结果是________

A)1 5 B)1 6 C)1 2 D)5 9

解析:

第一次执行 printf("%c", *p++);:

*p 是指向当前字符 '1',所以输出 '1'。

p++ 将指针 p 移动到下一个字符 '5'。

第二次执行 printf("%c", *p++);:

此时 p 指向字符 '5',所以输出 '5'。

p++ 将指针 p 移动到下一个字符 '9'。

解答:

A

1.6、有以下程序

point(char *p)

{

p+=3;

}

int main()

{ char b4={'a','b','c','d'}, *p=b;

point(p); printf("%c\n",*p);

}

程序运行后的输出结果是 __________

A)a B)b C)c D)d

解析:

当调用 point(p); 时,传递的是 p 的副本。因此,原始指针 pmain 函数中的值仍然指向字符数组 b 的第一个元素,即 'a'

解答:

A

1.7、设有如下定义语句 int m ={2,4,6,8}, *k=m;

以下选项中,表达式的值为 6的是

A *(k+2) B k+2 C *k+2 D *k+=2

解析:

A) *(k + 2)

k + 2 会指向 m2,也就是 6。

*(k + 2) 的值为 6。

结果: 是 6。

B) k + 2

k + 2 是指针运算,它会返回指向 m2 的地址。

这个表达式的值是指针,不是 6。

结果: 不是 6。

C) *k + 2

*k 是 m0,即 2。

*k + 2 的值为 2 + 2 = 4。

结果: 不是 6。

D) *k += 2

*k 是 m0,即 2。这个表达式会将 m0 的值更新为 4。

此时,该表达式的值是更新后的 4,而不是 6。

结果: 不是 6。

解答:

A

1.8、若有定义语句:int year=2009,*p=&year;,以下不能使变量 year 中的值增至 2010 的语 句是( )。

A)*p+=1; B)( *p)++; C)++(*p); D)*p++;

解析:

A) *p += 1;

这个语句会将 year 的值增加 1。

结果:year 变为 2010。

可以实现。

B) (*p)++;

这个语句会先返回 year 的值(2009),然后将 year 的值增加 1。

结果:year 变为 2010。

可以实现。

C) ++(*p);

这个语句会将 year 的值增加 1,等同于 *p += 1;。

结果:year 变为 2010。

可以实现。

D) *p++;

这个语句中的 *p++ 先返回 *p(即 year 的值 2009),然后 p 自增到指向下一个整型的位置。

这个操作不会改变 year 的值。

结果:year 仍然为 2009。

解答:

D

1.9、设有定义:double x10,*p=x;,以下能给数组 x 下标为 6 的元素读入数 据的正确语句是

A)scanf("%f",&x6); B)scanf("%lf",*(x+6));

C)scanf("%lf",p+6); D)scanf("%lf",p6);

解析:

A) scanf("%f", &x6);

%f 是用于读取 float 类型的格式符,而 x6 是 double 类型的。

这个语句是错误的,因为格式符与变量类型不匹配。

不正确。

B) scanf("%lf", *(x + 6));

*(x + 6) 表示访问 x6 的值,但这里不应该使用解引用操作符 *。

正确的方式是使用 & 来获取地址。

这个语句是错误的。

不正确。

C) scanf("%lf", p + 6);

p + 6 是指向 x6 的指针,而 %lf 是用于读取 double 类型的格式符。

这个语句是正确的,因为它可以直接将 x6 的地址传递给 scanf。

正确。

D) scanf("%lf", p6);

p6 等价于 *(p + 6),表示访问 x6 的值,而不是地址。

因此,这个语句也是错误的,因为它尝试将一个值传递给 scanf,而 scanf 需要一个地址。

不正确。

解答:

C

1.10、若有定义语句:char s310, (*k)3, *p; ,则以下赋值语句正确的是____

A)p=s; B)p=s0; C)p=k; D)k=s;

解析:

A) p = s;

s 是 char 类型的二维数组,代表 char (*)10(指向包含 10 个字符的数组的指针)。

p 是 char *,无法直接赋值。

不正确。

B) p = s0;

s0 是指向 s 的第一行的指针,类型是 char *。

这与 p 的类型相匹配,因此这个赋值是有效的。

正确。

C) p = k;

k 的类型是 char (*)3,指向包含 3 个字符的数组。

p 的类型是 char *,这两个类型不兼容。

不正确。

D) k = s;

s 的类型是 char (*)10(指向包含 10 个字符的数组的指针),与 k 的类型不匹配。

不正确。

解答:

B

1.11、有定义语句:int *p4; 以下选项中与此语句等价的是

A)int p4; B)int **p; C)int *(p4); D)int (*p)4;

解析:

int *p4; 定义了一个包含 4 个元素的数组 p,每个元素都是指向 int 的指针。也就是说,p 是一个指针数组,其中每个元素都指向一个 int 类型的值。

A) int p4;

这定义了一个包含 4 个 int 类型元素的数组。与 int *p4; 不相同。

不等价。

B) int **p;

这定义了一个指向指针的指针,表示一个指向 int * 类型的指针。与 int *p4; 不相同。

不等价。

C) int *(p4);

这与 int *p4; 等价,因为它同样定义了一个包含 4 个 int * 类型元素的数组(虽然书写方式不同,但意义相同)。

等价。

D) int (*p)4;

这定义了一个指向包含 4 个 int 元素的数组的指针,和 int *p4; 不同。

不等价。

解答:

C

1.12、若有定义语句:int a410, *p, *q4; 且 0≤i<4,则错误的赋值 是

A)p=a B)qi=ai C)p=ai D)p=&a21

解析:

选项A:p = a

a 是一个二维数组 int a410,在 C 语言中,a 的类型是 int (*)10(指向包含 10 个整数的一维数组的指针)。

p 是一个 int * 类型的指针。

在这种情况下,p = a 的赋值是 不合法 的,因为:

a 是一个指向一维数组的指针,不能直接赋值给一个指向单个 int 的指针 p。这种赋值会导致类型不匹配。

正确的赋值应该是 p = &a00,这样 p 才会指向数组的第一个元素。

解答:

A

1.13、若有以下定义

int x10,*pt=x;

则对 x 数组元素的正确应用是

A)*&x10 B)*(x+3)

3C)*(pt+10) D)pt+3

解析:

A)*&x10

x10 超出了数组的有效范围(合法索引为 0 到 9),因此访问 x10 是不合法的。

结果:不合法

B)*(x + 3)

x + 3 指向数组 x 的第四个元素(索引为 3)。

*(x + 3) 访问这个元素的值。

结果:合法,返回 x3 的值。

C)*(pt + 10)

pt + 10 超出了数组的有效范围(合法索引为 0 到 9),所以访问 *(pt + 10) 是不合法的。

结果:不合法

D)pt + 3

pt + 3 指向 x 数组的第四个元素(索引为 3),但此表达式本身不访问元素的值,只是计算地址。

结果:不合法,不直接返回数组元素的值。

解答:

B

1.14、有以下程序

#include <stdio.h>

main()

{ int a ={1,2,3,4},y,*p=&a3;

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

}

程序的运行结果是

A)y=0 B)y=1 C)y=2 D)y=3

解析:

数组 a 的定义为 {1, 2, 3, 4},索引从 0 到 3。

a0 = 1

a1 = 2

a2 = 3

a3 = 4

指针 p 初始化为指向 a3,即 p 的值为 &a3(地址值指向元素 4)。

执行 --p;,指针 p 现在指向 a2,即元素值 3。

y = *p; 解引用 p 得到 a2 的值,赋值给 y。所以 y = 3。

最后,printf("y=%d\n", y); 打印 y 的值。

解答:

D

1.15、设char *s = "\ta\017bc";则指针变量s指向的字符串所占的字节数是_______

A) 6 B) 2 C) 5 D) 9

解析:

\t 表示一个制表符(Tab),占用 1 个字节。

a 是一个普通字符,占用 1 个字节。

\017 是一个八进制数,表示字符 \017,对应的十进制值为 15,实际上是控制字符,占用 1 个字节。

b 是一个普通字符,占用 1 个字节。

c 是一个普通字符,占用 1 个字节。

字符串的结束符 \0,占用 1 个字节。

解答:

A

1.16、 若有定义语句:char s310, (*k)3, *p;,则以下赋值语句正确的是 A)p=s; B)p=k; C)p=s0; D)k=s;
解析:

A) p = s;

s 是 char 类型的二维数组,代表 char (*)10(指向包含 10 个字符的数组的指针)。

p 是 char *,无法直接赋值。

不正确。

C) p = s0;

s0 是指向 s 的第一行的指针,类型是 char *。

这与 p 的类型相匹配,因此这个赋值是有效的。

正确。

B) p = k;

k 的类型是 char (*)3,指向包含 3 个字符的数组。

p 的类型是 char *,这两个类型不兼容。

不正确。

D) k = s;

s 的类型是 char (*)10(指向包含 10 个字符的数组的指针),与 k 的类型不匹配。

不正确。

解答:

C

2、填空题

2.1以下程序的输出结果是_______

#include<stdio.h>

main()

{ int a5={2,4,6,8,10}, *p;

p=a+2;

printf("%d",*p++);

}

解析:

数组初始化:

int a5 = {2, 4, 6, 8, 10};:数组 a 被初始化为 2, 4, 6, 8, 10。

指针赋值:

p = a + 2;:指针 p 指向数组 a 的第三个元素(a2),即 6。

打印输出:

printf("%d", *p++);:

*p 取出 p 指向的值(即 6)。

p++ 后缀自增,指针 p 将指向下一个元素(a3,值为 8)。

因此,输出 6。

解答:

6

2.2、以下程序段的定义语句中,x1的初值是_____,程序运行后输出的内容是_______

#include<stdio.h>

main()

{ int x\[\]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},*p4,i;

for(i=0;i<4;i++)

{ pi=&x2\*i+1; printf("%d ",pi0);

}

printf("\n");

}

解析:

数组 x 的初始化:

x 被初始化为 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16。

x1 的初值:

因此,x1 的初值是 2。

在 for 循环中,指针 pi 被赋值为 &x2\*i + 1

当 i = 0:

p0 = &x2\*0 + 1 = &x1,此时 p0 指向 x1(值为 2)。

输出 p00,即 *p0,结果为 2。

当 i = 1:

p1 = &x2\*1 + 1 = &x3,此时 p1 指向 x3(值为 4)。

输出 p10,即 *p1,结果为 4。

当 i = 2:

p2 = &x2\*2 + 1 = &x5,此时 p2 指向 x5(值为 6)。

输出 p20,即 *p2,结果为 6。

当 i = 3:

p3 = &x2\*3 + 1 = &x7,此时 p3 指向 x7(值为 8)。

输出 p30,即 *p3,结果为 8。

解答:

2 2468

2.3 以下程序段的输出结果是**( )**

#include <sthio.h>

mian()

{ char *ch4={"red","green","blue"}; int i=0;

while(chi);

{ putchar(chi0; i++; }

}

解析:

字符指针数组 ch:

char *ch4 = {"red", "green", "blue", NULL}; 这是一个字符指针数组,存储了三个字符串和一个 NULL 指针,用于标识数组的结束。

while (chi) 循环:

循环的条件是 chi,它会检查 chi 是否为 NULL。如果不是,则继续执行循环。

输出 putchar(chi0):

chi0 获取字符串 chi 的第一个字符。

对于字符串数组中的每个字符串,输出其首字符:

当 i = 0 时,ch0 是 "red",输出 r。

当 i = 1 时,ch1 是 "green",输出 g。

当 i = 2 时,ch2 是 "blue",输出 b。

当 i = 3 时,ch3 是 NULL,循环结束。

解答:

rgb

2.4、以下程序的功能是:借助指针变量找出数组元素中最大值所在的位置并输出该最大值。 请在输出语句中填写代表最大值的输出项。

#include <stdio.h>

int main()

{ int a10, *p, *s;

for(p=a; p-a<10; p++)

scanf("%d", p);

for(p=a,s=a;p-a<10;p++)

if(*p>*s) s=p;

printf("max=%d, 序号:%d\n" , ___________ );

}

解析:

输入数组:使用 scanf 输入 10 个整数。

查找最大值:

使用两个指针 p 和 s,其中 s 初始化为指向数组的起始位置,p 遍历整个数组。

在循环中,如果当前指针 p 所指向的值大于 s 所指向的值,则更新 s,使其指向当前更大的值。

输出最大值和序号:

*s:表示最大值。

s - a:表示最大值在数组中的索引位置。

解答:

*s,s-a

2.5 有以下程序,输出结果为_________

main()

{

int a5={1,2,3,4,5};

int *ptr=(int *)(&a+1);

printf("%d,%d",*(a+1),*(ptr-1));

}

解析:

数组定义:

int a5 = {1, 2, 3, 4, 5}; 定义了一个包含五个整数的数组 a。

指针定义:

int *ptr = (int *)(&a + 1);

&a 是数组 a 的地址,其类型是 int (*)5(指向数组的指针)。

&a + 1 的效果是获取 a 数组之后的内存地址,这个地址是 a 的末尾加上整个数组的大小(即 5 个 int 的大小,通常是 20 字节,假设 int 是 4 字节)。

由于 &a + 1 结果是一个指向 int5 的指针,因此在进行强制类型转换后,ptr 实际指向的是 a 数组之后的第一个 int(即 a5)。

打印输出:

*(a + 1):

这个表达式指向 a 数组的第二个元素,值是 2。

*(ptr - 1):

ptr - 1 实际上是指向 a4(数组的最后一个元素),值是 5。

解答:

2,5

2.6 以下程序的功能是:借助指针变量找出数组元素中最大值所在的位置并输出该最大值。 请在输出语句中填写代表最大值的输出项。

#include <stdio.h>

int main( )

{ int a10, *p, *s;

for(p=a;p-a<10; p++)

scanf("%d",p);

for(p=a,s=a;p-a<10;p++)

if(*p>*s) s=p;

printf("max=%d\n" , ______ );

解析:

输入数组:使用 scanf 输入 10 个整数。

查找最大值:

使用两个指针 p 和 s,其中 s 初始化为指向数组的起始位置,p 遍历整个数组。

在循环中,如果当前指针 p 所指向的值大于 s 所指向的值,则更新 s,使其指向当前更大的值。

输出最大值和序号:

*s:表示最大值。

s - a:表示最大值在数组中的索引位置。

解答:

*s,s-a

3、编程题

3.1、 有一个整型数组int 10 = {10,20,30,40,50,60,70,80,90,100};标准输入一个整型数值m(0<m<10) ,使前面10-m个数值向后移动m个位置,最后m个数变成前面的m个数
代码解答:
cpp 复制代码
#include <stdio.h>

int main() {
    int arr[10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    int m;

    // 输入m的值,确保0 < m < 10
    printf("请输入一个整数 m (0 < m < 10): ");
    scanf("%d", &m);
    
    // 检查输入的合法性
    if (m <= 0 || m >= 10) {
        printf("输入不合法!m的值必须在0到10之间。\n");
        return 1; // 结束程序
    }

    // 移动数组
    // 从后往前移动
    for (int i = 9; i >= m; i--) {
        arr[i] = arr[i - m];
    }

    // 将最后m个数变成前面的m个数
    for (int i = 0; i < m; i++) {
        arr[i] = 10 * (i + 1); // 将前m个数设为10, 20, 30, ...
    }

    // 输出结果
    printf("移动后的数组为:");
    for (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

作业三

结构体共用体练习

选择题

1.1、设有以下语句:

typedef struct REC

{

char c;

int a4;

}REC1;

则下面叙述中正确的是____________。

A)可以用REC定义结构体变量

B)REC1是struct REC类型的变量

C)REC是struct 类型的变量。

D)可以用REC1定义结构体变量

解析:

A)可以用 REC 定义结构体变量

错误。REC 是结构体的标签名,而不是类型名。你需要使用 struct REC 来定义结构体变量。

B)REC1 是 struct REC 类型的变量

错误。REC1 是 struct REC 的别名,不是变量。它是一个类型名。

C)REC 是 struct 类型的变量

错误。REC 是结构体的标签名,不是变量。结构体变量需要显式地定义,比如 struct REC myVar;。

D)可以用 REC1 定义结构体变量

正确。因为 REC1 是 struct REC 的别名,所以你可以使用 REC1 来定义结构体变量,如 REC1 myVar;。

解答 :

D

1.2、下列关于结构的说法错误的是______.

A)结构是由用户自定义的一种数据类型。

B)结构中可设定若干个不同数据类型的成员。

C)结构中成员的数据类型可以是另一个已定义的结构

D)在定义结构时,可以为成员设置默认值。

解析:

A) 结构是由用户自定义的一种数据类型。

正确。结构确实是用户定义的一种数据类型,可以包含多个成员。

B) 结构中可设定若干个不同数据类型的成员。

正确。结构的成员可以是不同的数据类型,例如整型、字符型、浮点型等。

C) 结构中成员的数据类型可以是另一个已定义的结构。

正确。结构的成员可以是其他结构类型,这样可以实现嵌套结构。

D) 在定义结构时,可以为成员设置默认值。

错误。在 C 语言中,不能直接在结构定义时为成员设置默认值。需要在定义结构变量后,通过赋值来设置成员的值。

解答 :

D

1.3、以下结构体类型说明和变量定义中,正确的是______。

A) struct SS B) struct

{ {

char flag; char flag;

float x; float x;

} }SS;

struct SS a, b;

C) struct ss D)typedef

{ {

char flag; char flag;

float x; float x

}; }SS;

struct ss a,b; SS a,b;

解析:

A)在定义结构体时少了个`;`

B)struct 关键字后面缺少结构体的名称。正确的写法应该是 struct SS

C)正确

D)typedef 语句的写法不正确。typedef 后面需要跟 struct 类型的完整定义,且结构体变量的定义也有错误,正确写法应该是 typedef struct { ... } SS;,然后可以用 SS a, b; 来声明变量。

解答 :
C
1.4、设有以下说明语句:

struct stu

{

int a;

float b;

}stutype;

则下面的叙述不正确的是____________。

A)struct是结构体类型的关键字

B)struct stu是用户定义的结构体类型名

C)stutype 是用户定义的结构体类型名

D)a 和b 都是结构体成员名

解析:

A) 正确。struct 确实是结构体类型的关键字。

B) 正确。struct stu 是结构体类型的声明,其中 stu 是用户定义的结构体类型名。

C) 错误。stutype 是结构体的类型定义,并不是用户定义的结构体类型名。实际上,stutype 是该结构体类型的一个别名。

D) 正确。a 和 b 确实是结构体成员名

解答 :

C

1.5、根据下面的定义,能打印出字母M的语句是____________。

struct person

{

char name9;

int age;

};

struct person class10 = {"John",17,"Paul",19,"Mary",18,"adam",16};

A) printf("%c\n",class3.name);

B) printf("%c\n",class3.name1);

C) printf("%c\n",class2.name1);

D) printf("%c\n",class2.name0);

解析:

A) printf("%c\n",class3.name);

这将尝试打印 class3.name,这是一个字符串(字符数组),会导致类型不匹配错误。

B) printf("%c\n",class3.name1);

class3.name 对应的字符串是 "adam",name1 是 'd',因此不会打印出 M。

C) printf("%c\n",class2.name1);

class2.name 对应的字符串是 "Mary",name1 是 'a',因此不会打印出 M。

D) printf("%c\n",class2.name0);

class2.name 对应的字符串是 "Mary",name0 是 'M',所以这条语句将打印出字母 M。

解答 :

D

1.6、若有如下定义:

struct person

{

int id;

char name10;

}per,*s = &per;

则以下对结构体成员的引用中错误的是____________。

A) per.name B) s->name0

C) (*per).name8 D) (*s).id

解析:

A) per.name

这是一个正确的引用,直接访问 per 的 name 成员。

B) s->name0

这是一个正确的引用,使用箭头运算符(->)访问指针 s 指向的结构体的 name 成员。

C) (*per).name8

这是错误的引用。这里的 per 是一个结构体变量,而不是指针,因此不能使用解引用操作符 *。正确的写法应为 (*s).name8 或 s->name8

D) (*s).id

这是一个正确的引用,使用解引用操作符访问指针 s 指向的结构体的 id 成员。

解答 :

C

1.7、下面程序的运行结构是____________。

main()

{

struct cmplx{int x;

int y;

}cnum2 = {1,3,2,7};

printf("%d\n",cnum0.y/cnum0.x*cnum1.x);

}

A)0 B)1 C)3 D)6

解析:

结构体初始化:

cnum0 初始化为 {1, 3},即 cnum0.x = 1 和 cnum0.y = 3。

cnum1 初始化为 {2, 7},即 cnum1.x = 2 和 cnum1.y = 7。

计算表达式:

首先计算 cnum0.y / cnum0.x:

cnum0.y/cnum0.x=3/1=3

cnum0.y/cnum0.x=3/1=3

然后乘以 cnum1.x:

3∗cnum1.x=3∗2=6

3∗cnum1.x=3∗2=6

输出结果:

程序输出 6。

解答 :

D

1.8、若有以下定义和语句:

struct student

{

int age;

int num;

};

struct student stu3 = {{1001,20},{1002,19},{1003,21}};

main( )

{

sturct student *p;

p = stu;

...

}

则以下不正确的引用形式是____________。

A) (p++) ->num B) p++

C) (*p).num D) p = &stu.age

解析:

A) (p++) -> num

合法:这个表达式首先访问指针 p 指向的 num 成员,然后将 p 增加到下一个 student 结构体(这通常是有效的,尽管需要注意这种用法在某些情况下会导致未定义行为)。

B) p++

合法:这个表达式增加指针 p,将其指向下一个 student 结构体。

C) (*p).num

合法:这个表达式解引用指针 p 并访问 num 成员。

D) p = &stu.age

不合法:stu 是一个结构体数组,stu.age 不是有效的表达式。结构体数组的成员必须通过索引来访问。例如,应该使用 stu0.age 来获取第一个结构体的 age 成员的地址

解答 :

D

1.9、设有以下定义和语句,以下引用形式不合法的是____________。

struct s

{

int il;

struct s *i2;

char *i0;

};

static struct s a3 = {2,&a1,'\0',4,&a2, '\0' , 6 ,&a1, '\0' },*ptr;

ptr = a;

A) ptr->i1++ B) *ptr->i2 C) ++ptr->i0 D) *ptr->i1

解析:

A) ptr->i1++

合法:这个表达式对 ptr 所指向的结构体的 i1 成员进行自增操作。

B) *ptr->i2

合法:ptr->i2 返回指向另一个 struct s 的指针,*ptr->i2 解引用该指针。

C) ++ptr->i0

合法:ptr->i0 是一个指向字符的指针,因此可以对其进行自增操作,指向下一个字符。

D) *ptr->i1

不合法:ptr->i1 是一个 int 类型的成员,不能解引用。解引用只能用于指针类型。

解答 :

D

1.10、设有如下定义:

struct sk

{

int n;

float x;

}data,*p;

若要使p指向data中的n域,则正确的赋值语句是____________。

A) p = &data.n; B) *p = data.n;

C) p =(struct sk *)&data.n; D) p = (struct sk *)data.n;

解析:

A) p = &data.n;

不合法:&data.n 是一个指向 int 的指针,但 p 是指向 struct sk 的指针。

B) *p = data.n;

不合法:*p 期望一个 struct sk 类型的值,但 data.n 是 int 类型,类型不匹配。

C) p =(struct sk *)&data.n;

合法:&data.n 是一个指向 int 的指针,强制转换为 struct sk * 是合适的,因为它们的类型不同。

D) p = (struct sk *)data.n;

不合法:data.n 是 int 类型,强制转换为 struct sk * 不合适,可能会导致不正确的内存访问。

解答 :

C

1.11、若有以下程序段:

struct dent

{

int n;

int *m;

};

int a = 1,b = 2,c = 3;

struct dent s3 = {{101,&a},{102,&b},{103,&c}};

main()

{

struct dent *p;

p =s;

...

}

则以下表达式中值为2的是____________。

A) (++p)->m B) *(p++)->m

C) (*p).m D) *(++p)->m

解析:

A) (++p)->m

p 指向 s0,执行 ++p 后,p 指向 s1

p->m 是 s1.m,即 &b,其值为 2。

值为 2。

B) *(p++)->m

p 指向 s0,首先解引用 p,p->m 是 s0.m,即 &a,其值为 1。

然后 p++ 会使 p 指向 s1。所以这个表达式返回的是 *(&a) 的值,结果为 1。

值为 1。

C) (*p).m

此时 p 指向 s0,(*p).m 是 s0.m,即 &a,值为 1。

值为 1。

D) *(++p)->m

p 指向 s0,执行 ++p 后,p 指向 s1

*(p->m) 是 *(s1.m),即 *(&b),值为 2。

值为 2。

解答 :

AD

1.12、若有以下说明和语句,则对pup中sex域的正确引用方式是____________

struct pupil

{

char name20;

int sex;

}pup,*p;

p = &pup;

A) p.pup.sex B) p->pup.sex

C) (*p).pup.sex D) (*p).sex

解析:

A) p.pup.sex

p 是指针,不能用点运算符(.)直接引用。此写法不合法。

错误。

B) p->pup.sex

p 是指向 pup 的指针,p->pup 表示对 pup 的引用,但 pup 是结构体变量而不是结构体成员。这个表达式是不合法的。

错误。

C) (*p).pup.sex

(*p) 是 pup 的引用,但同样 (*p).pup 是不合法的,因为 pup 是结构体变量而不是结构体成员。

错误。

D) (*p).sex

(*p) 解引用指针 p,得到 pup 结构体,然后可以直接访问 sex 域。

这是合法且正确的引用方式。

正确。

解答 :

D

1.13、以下程序的输出结果是____________。

struct stu

{

int x;

int *y;

}*p;

int dt4 = {10,20,30,40};

struct stu a4 = {50,&dt0,60,&dt1,70,&dt2,80,&dt3};

main( )

{

p = a;

printf("%d,",++p->x);

printf("%d",(++p)->x);

printf("%d",++(*p->y));

}

A)10,20,20 B)50,60,21

C)51,60,21 D)60,70,31

解析:

第一行: printf("%d,", ++p->x);

p 最初指向 a0,即 x = 50。

++p->x 会先将 p->x(即 a0.x)加 1,然后输出 51。

此时 a0.x 的值变为 51。

输出: 51

第二行: printf("%d", (++p)->x);

++p 将 p 移动到 a1,即 x = 60。

输出 60。

输出: 60

第三行: printf("%d", ++(*p->y));

此时 p 仍然指向 a1

p->y 指向 dt1,即 y = 20。

++(*p->y) 将 dt1 的值加 1,变为 21。

输出: 21

解答 :

C

1.14、若有以下说明和语句,则下面表达式中值为1002的是____________。

struct student

{

int age;

int num;

};

struct student stu3 = {{1001,20},{1002,19},{1003,21}};

struct student *p;

p = stu;

A) (p++)->num B) (p++)->age

C) (*p).num D) (*++p).age

解析:

A) (p++)->num

p++ 先使用 p 的当前值(stu0),然后将 p 指向 stu1

p->num 为 20(stu0.num),所以输出是 20,不是 1002。

B) (p++)->age

同样,p++ 先使用 stu0,然后将 p 指向 stu1

p->age 为 1001(stu0.age),所以输出是 1001,不是 1002。

C) (*p).num

此时 p 仍然指向 stu0,所以 (*p).num 为 20,不是 1002。

D) (*++p).age

++p 将 p 移动到 stu1

(*p).age 为 1002(stu1.age),所以输出是 1002。

解答 :

D

1.15、以下对结构体变量stu1中成员age的非法引用是____________。

struct student

{

int age;

int num;

}stu1,*p;

p = &stu1;

A) stu1.age B) student.age

C) p ->age D) (*p).age

解析:

A) stu1.age

这是合法的引用,直接访问 stu1 中的 age 成员。

B) student.age

这是非法的引用。student 是结构体类型名,而不是变量名。不能直接通过结构体类型名访问结构体成员。

C) p->age

这是合法的引用。指针 p 指向 stu1,通过箭头运算符可以访问 age 成员。

D) (*p).age

这是合法的引用。解引用指针 p 后可以通过点运算符访问 age 成员

解答 :

B

1.16、 设有以下说明和定义语句,则下面表达式中值为3的是____________

struct s

{

int il;

struct s *i2;

};

static struct s a3 = {1,&a1,2,&a2,3,&a0},*ptr;

ptr = &a1;

A)ptr->il++ B)ptr++->il

C)(ptr++)->il D)++ptr->il

解析:

A) ptr->il++

ptr->il 的当前值为 2,执行 ptr->il++ 后,值变为 3,并且返回的值是 2。所以这个表达式的结果不是 3。

B) ptr++->il

先计算 ptr->il,此时 ptr 指向 a1,所以返回值为 2,然后 ptr 移动到下一个元素(指向 a2)。所以返回值不是 3。

C) (ptr++)->il

这个表达式与选项 B 类似,首先返回 ptr->il 的值,即 2,然后再进行指针自增。返回值不是 3。

D) ++ptr->il

这个表达式会首先对 ptr->il 进行自增,ptr 指向 a1,ptr->il 从 2 自增到 3,并返回自增后的值 3。

解答 :

D

1.17、若有以下定义和语句:

union data

{

int i;

char c;

float f;

}a;

int n;

则以下语句正确的是____________。

A)a = 5; B)a.f = 1.2

C)printf("%d\n",a); D)n =a;

解析:

A) a = 5;

这是错误的,因为 a 是一个联合体,无法直接赋值为一个整数。正确的写法应该是使用 a.i = 5;。

B) a.f = 1.2;

这是正确的,虽然可能会引起类型问题(由于不同数据类型共用同一内存位置),但语法上是合法的。

C) printf("%d\n", a);

这是错误的,因为 a 是一个联合体,不能直接作为 %d 的参数。你需要使用 a.i 来打印 int 类型的值,例如 printf("%d\n", a.i);。

D) n = a;

这是错误的,因为不能将一个联合体直接赋值给一个整数变量。需要使用 n = a.i;。

解答 :

B

1.18、以下程序在32位操作系统的运行结果是____________。

#include <stdio.h>

main( )

{

union{

long a;

int b;

char c;

}m;

printf("%d\n",sizeof(m));

}

A) 2 B)4 C) 6 D)8

解析:

long 类型:在32位操作系统上,通常为4字节。

int 类型:在32位操作系统上,通常为4字节。

char 类型:大小为1字节。

由于联合体的大小取决于其最大成员的大小,且在32位系统上 long 和 int 的大小都是4字节,因此联合体 m 的大小将是4字节。

解答 :

B

1.19、以下程序的运行结果是____________

#include <stdio.h>

union pw

{

int i;

char ch2;

}a;

main( )

{

a.ch0 = 13;

a.ch1 = '0';

printf("%d\n",a.i);

}

A) 12301 B)4813 C) 208 D) 209

解析:

内存布局分析

a.ch0 被赋值为 13,其十六进制表示为 0x0D。

a.ch1 被赋值为字符 '0',其 ASCII 值为 48,十六进制表示为 0x30。

联合体的内存结构通常是按照小端字节序(little-endian)存储的:

a.ch0(低位字节)存储在地址的低位,即 0x0D。

a.ch1(高位字节)存储在地址的高位,即 0x30。

计算 a.i

在小端字节序下,a.i 的内存布局如下:

低位(ch0):0x0D (13)

高位(ch1):0x30 (48)

将这两个字节合并为一个整数 i:

a.i=0x30×256+0x0D=48×256+13=12288+13=12201

解答 :

A

1.20、下面对typedef的叙述中不正确的是____________

A) 用typedef可以定义各种类型名,但不能用来定义变量

B) 用typedef可以增加新类型

C) 用typedef只是将已存在的类型用一个新的标识符来代表

D) 使用typedef有利于程序的通用和移植

解析:

A) 用typedef可以定义各种类型名,但不能用来定义变量

正确。typedef 用于为现有类型创建别名,不能直接用于定义变量。

B) 用typedef可以增加新类型

不正确。typedef 不能创建新的数据类型,它只是为现有类型提供新的名称。

C) 用typedef只是将已存在的类型用一个新的标识符来代表

正确。typedef 创建的只是类型的别名,实际上没有创建新的类型。

D) 使用typedef有利于程序的通用和移植

正确。通过使用 typedef,可以使代码更易读并增强移植性,因为可以在不同的平台上使用不同的类型实现。

解答 :

B

1.21、下面程序在64位操作系统的运行结果是____________。

typedef union { long a2;

int b4;

char c8;

}TY;

TY our;

main()

{

printf("%d\n",sizeof(our));

}

A) 32 B)16 C) 8 D)24

解析:

在这个程序中,TY 是一个 union,其成员包括:

一个包含 2 个 long 类型元素的数组 a2

一个包含 4 个 int 类型元素的数组 b4

一个包含 8 个 char 类型元素的数组 c8

union 的大小由其最大成员决定。在 64 位操作系统中:

一个 long 类型通常占用 8 字节,因此 a2 占用 16 字节。

一个 int 类型通常占用 4 字节,因此 b4 占用 16 字节。

一个 char 类型占用 1 字节,因此 c8 占用 8 字节。

因此,union TY 的大小取决于其最大成员 a2,即 16 字节。因此,sizeof(our) 将返回 16。

解答 :

B

二、填空题

2.1、有结构体

struct ST

{

int a;

float b;

sturct ST *c;

double x3;

}st1;

请填空,完成以下对数组s的定义,使其每个元素均为上述结构体类型。

____________ s10;

解析:

要定义一个包含结构体 ST 类型元素的数组 s,需要将结构体 ST 的定义放在数组定义之前

解答 :

struct ST

2.2、 以下程序的运行结果是____________。

struct n

{ int x;

char c;

};

main( )

{

struct n a = {10,'x'};

func(a);

printf("%d,%c",a.x,a.c);

}

func(struct n b)

{

b.x = 20;

b.c = 'y';

}

解析:

没传地址,所以原变量不变

解答 :

10 x

2.3、以下程序的运行结果是_____

main()

{

struct EXAMPLE

{

struct{ int x;

int y;

}in;

int a;

int b;

}e;

e.a = 1; e.b = 2;

e.in.x = e.a*e.b;

e.in.y = e.a +e.b;

printf("%d,%d",e.in.x,e.in.y);

}

解析:

e.in.x 被赋值为 e.a 和 e.b 的乘积,即 1 * 2 = 2。

e.in.y 被赋值为 e.a 和 e.b 的和,即 1 + 2 = 3。

解答 :

2,3

2.4、 以下程序的输出结果是____________。

#include <stdio.h>

struct abc

{

char c;

float v;

};

void fun1(strcut abc b)

{

b.c = 'A';

b.v = 80.7;

}

void fun2(struct abc *b)

{

(*b).c = 'C';

(*b).v = 92.5;

}

int main()

{

struct abc a = {'B',98.5};

fun1(a);

printf("%c,%4.1f\n",a.c,a.v);

fun2(&a);

printf("%c,%4.1f\n",a.c,a.v);

}

解析:

fun1是值传送,原变量不变,fun2是地址传送原变量发生改变

解答 :

B, 98.5

C, 92.5

2.8、若已定义:

struct num

{

int a;

int b;

float f;

} n = {1,3,5.0}

struct num *pn = &n;

则表达式pn->b/n.a*++pn->b的值是++【++ ++1++ ++】++ ,表达式(*pn).a + pn->f的值是++【++ ++2++ ++】++。

解析:

初始状态:

n.a = 1

n.b = 3

n.f = 5.0

pn 指向 n。

解析:

pn->b 当前值为 3。

n.a 的值为 1。

++pn->b 将 pn->b 先自增,然后使用新值。自增操作会使 n.b 从 3 变为 4。

因此:

pn->b 变为 4(自增后)。

pn->b / n.a 计算为 4 / 1 = 4。

最终表达式的值为 4 * 4 = 16。

  1. 表达式 (*pn).a + pn->f

解析:

(*pn).a 是 n.a 的值,等于 1。

pn->f 是 n.f 的值,等于 5.0。

因此:

这个表达式计算为 1 + 5.0 = 6.0。

总结

第一个表达式 pn->b / n.a * ++pn->b 的值是 16。

第二个表达式 (*pn).a + pn->f 的值是 6.0。

解答 :

16,6.0

2.9、以下程序的运行结果是____________。

struct ks

{

int a;

int *b;

} s4,*p;

main()

{

int n = 1,i;

printf("\n");

for(i = 0;i < 4;i++)

{

si.a = n;

si.b = &si.a;

n = n+2;

}

p = &s0;

p++;

printf("%d,%d\n",(++p)->a, (p++)->a ) ;

}

解析:

在 for 循环中:

s0.a = 1

s1.a = 3

s2.a = 5

s3.a = 7

对应的指针 b 均指向各自的 a 成员。 ++p 使 p 指向 s2,然后访问 s2.a 的值,即 5。

(p++)->a 先访问当前 p 指向的 s2 的 a 的值(即 5),然后 p 自增到 s3

因此,printf 的输出将是:

第一个 %d 输出 5(来自 s2.a)。

第二个 %d 输出 5(来自 s2.a,因为 p++ 操作在这一步之后才改变 p 的指向)。

解答 :

5,5

2.10、以下程序的运行结果为____________

struct s

{

int a;

float b;

char *c;

}

main( )

{

static struct s x = {19,83.5,"zhang"};

struct s *px = &x;

printf("%d%.1f%s\n",x.a,x.b,x.c);

printf("%d%.1f%s\n",px->a,(*px).b,px->c);

printf("%c%s\n",*px->c-1,&px->c1);

}

解析:

第一个 printf 语句

x.a 输出 19。

x.b 输出 83.5,使用 .1f 格式输出,显示为 83.5。

x.c 输出字符串 "zhang"

第二个 printf 语句:

px->a 输出 19(和 x.a 一样)。

(*px).b 输出 83.5(和 x.b 一样)。

px->c 输出字符串 "zhang"(和 x.c 一样)

第三个 printf 语句

*px->c 访问的是 x.c 的第一个字符,即 'z',然后减去 1,得到字符 'y'。

&px->c1 指向字符串 "zhang" 的第二个字符,即 "hang"

解答 :

19 83.5zhang

19 83.5zhang

yhang

2.11、设有以下定义和语句,请在printf语句的【】中天上能够正确输出的变量及相应的格式说明。

union

{

int n;

double x;

}num;

num.n = 10;

num.x = 10.5;

printf("++【++ ++1++ ++】++ ",++【++ ++2++ ++】++);

解析:

输出 num.n

如果我们尝试输出 num.n,我们会得到一个未定义的结果,因为 num.x 被赋值为 10.5,并且 num.n 的值是不可预知的。

输出 num.x

输出 num.x 是有效的,因为 num.x 是最近赋值的成员。

解答 :

printf("%f", num.x);

2.12、以下程序的运行结果是____________。

main()

{

struct EXAMPLE

{

union

{

int x;

int y;

}in;

int a;

int b;

}e;

e.a = 1; e.b = 2;

e.in.x = e.a *e.b;

e.in.y = e.a +e.b;

printf("%d,%d",e.in.x,e.in.y);

}

解析:

联合体的所有成员共享同一块内存,这意味着在联合体中赋值的最后一个成员会覆盖之前赋值的成员。

在这里,当我们执行 e.in.y = e.a + e.b; 时,由于 in 是一个联合体,e.in.y 的赋值将覆盖 e.in.x 的值。虽然 e.in.x 被赋值为 2,但在下一行代码中,e.in.y 被赋值为 3,此时 e.in.x 的值实际上是 3。

解答 :

3,3

2.13、以下程序的运行结果是____________。

union ks

{

int a;

int b;

};

union ks s4;

union ks *p;

main( )

{

int n = 1,i;

printf("\n");

for(i = 0;i < 4;i++)

{

si.a = n;

si.b = si.a + i;

n = n+2;

}

p = &s2;

printf("%d,",p++->a);

printf("%d",++p->a);

}

解析:

联合体数组初始化:

s0

s0.a = 1

s0.b = 1 + 0 = 1(s0.b 取值是 1,覆盖了 s0.a)

s1

s1.a = 3

s1.b = 3 + 1 = 4(s1.b 取值是 4,覆盖了 s1.a)

s2

s2.a = 5

s2.b = 5 + 2 = 7(s2.b 取值是 7,覆盖了 s2.a)

s3

s3.a = 7

s3.b = 7 + 3 = 10(s3.b 取值是 10,覆盖了 s3.a)

最终状态:

s0:a = 1, b = 1

s1:a = 4, b = 4

s2:a = 7, b = 7

s3:a = 10, b = 10

指针操作:

p = &s2;,指向 s2(p->a 为 7)。

解答 :

7,11

2.14、以下程序的运行结果是____________

main( )

{

union EXAMPLE

{

struct

{

int x;

int y;

}in

int a;

int b;

}e;

e.a = 1;

e.b = 2;

e.in.x = e.a * e.b;

e.in.y = e.a +e.b;

printf("%d %d",e.in.x,e.in.y);

}

解析:

定义和初始化联合体:

联合体 EXAMPLE 中有一个结构体 in,包含两个整数 x 和 y,以及两个整数 a 和 b。

由于这是一个联合体,a、b、in.x 和 in.y 共用同一块内存。

赋值操作:

e.a = 1;:设置 e.a 为 1。此时 e.b 和结构体成员 in 的内容不确定,因为联合体的成员共享内存。

e.b = 2;:设置 e.b 为 2。由于 a 和 b 是联合体的成员,所以此时 e.a 的值可能会被覆盖,但在这一点上我们关注的是后面的计算。

e.in.x = e.a * e.b;:这里的计算中,e.a 和 e.b 的值都分别为 1 和 2。所以 e.in.x 的值为 1 * 2 = 2。

e.in.y = e.a + e.b;:这里的计算中,e.a 和 e.b 的值都分别为 1 和 2。所以 e.in.y 的值为 1 + 2 = 3。

联合体内存重用:

由于 in 结构体和 a、b 共享内存,后面的赋值可能会影响值。在这个过程中,in.x 和 in.y 被赋值,但实际上因为是联合体,只有最后一个写入的值有效。即使我们在赋值之前对 e.a 和 e.b 进行了操作,实际上 e.in.y 在这里并不会被赋值为 3,而是被 e.in.x 所覆盖。

打印输出:

printf("%d %d", e.in.x, e.in.y); 在这里可能会输出 4 和 8,原因在于内存共享导致后面的值覆盖了之前的值。

最后,由于 in.x 和 in.y 共享内存,它们最终可能会取到我们未预见的值(具体依赖于编译器、内存对齐等)。

解答 :

4,8

2.15、以下程序的运行结果为____________。

#include <stdio.h>

struct w

{

char low;

char high;

};

union u

{

struct w byte;

int word;

}uu;

int main( )

{

uu.word = 0x1234;

printf("Word value:%04x\n",uu.word);

printf("High value:%02x\n",uu.byte.high);

printf("Low value:%02x\n",uu.byte.low);

uu.byte.low = oxff;

printf("Word value: %04x\n",uu.word);

}

解析:

联合体的定义:

struct w 定义了一个结构体,包含两个 char 类型的成员 low 和 high。

union u 定义了一个联合体,包含 struct w 和一个 int 类型的 word。联合体的所有成员共享同一块内存。

将值赋给联合体

uu.word = 0x1234; 将 0x1234(十六进制数,等于4660)存入联合体的 word 成员。

在大端字节序(big-endian)系统中,0x1234 将存储为:

high: 0x12

low: 0x34

打印输出:

printf("Word value:%04x\n", uu.word); 输出 Word value:1234。

printf("High value:%02x\n", uu.byte.high); 输出高字节,结果为 12。

printf("Low value:%02x\n", uu.byte.low); 输出低字节,结果为 34。

修改低字节:

uu.byte.low = 0xff; 将联合体中的低字节设置为 0xff。在内存中,word 的值将被更新为:

高字节仍然为 0x12,低字节现在为 0xff。

所以现在 word 的值为 0x12ff。

最后输出:

printf("Word value: %04x\n", uu.word); 输出 Word value:12ff。

解答 :

1234

12

34

12ff

2.16、以下程序的输出结果为____________

enum coin{ penny, nickel, dime, quarter, half_dollar, dollar };

char *name\[\] =

{"penny","nickel","dime","quarter","half_dollar","dollar"};

main( )

{

enum coin money1,money2;

money1 = dime;

money2 = dollar;

printf("%d %d\n",meney1,money2)

printf("%s %s\n",name(int)money1,name(int)money2);

}

解析:

枚举类型定义

在这里定义了一个枚举类型 coin,枚举的值分别是:

penny = 0

nickel = 1

dime = 2

quarter = 3

half_dollar = 4

dollar = 5

字符指针数组定义

这里定义了一个字符指针数组 name,用于存储对应的枚举名称。

枚举变量赋值

将 money1 设置为 dime,值为 2;将 money2 设置为 dollar,值为 5

打印输出

输出 money1 和 money2 的整数值,结果为 2 5

访问字符串数组

name(int)money1:(int)money1 的值是 2,因此输出 name2,对应的字符串为 "dime"。

name(int)money2:(int)money2 的值是 5,因此输出 name5,对应的字符串为 "dollar"。

解答 :

2 5

dime dollar

2.17、以下程序的输出结果是____________。

#include <stdio.h>

typedef int INT;

int main()

{

INT a,b;

a = 5;

b = 6;

printf("a = %d\tb = %d\n",a,b);

{

float INT;

INT = 3.0;

printf("2*INT = %.2f\n",2*INT);

}

}

解析:

类型定义:

typedef int INT;

使用 typedef 定义了一个新类型 INT,它是 int 的别名。因此,在程序中使用 INT 等价于使用 int。

变量声明和赋值:

INT a, b;

a = 5;

b = 6;

这里定义了两个 INT 类型的变量 a 和 b,并将它们赋值为 5 和 6。

打印变量值:

printf("a = %d\tb = %d\n", a, b);

输出为:

a = 5 b = 6

进入新作用域:

{

float INT;

INT = 3.0;

在这个新作用域中,INT 被重新定义为 float 类型。这会遮蔽前面的 typedef 定义,所以在这个作用域中 INT 不再是 int 的别名,而是一个 float 类型的变量。

计算并打印:

printf("2*INT = %.2f\n", 2 * INT); // 计算 2 * INT 的值,并打印

这里 INT 是 float 类型,并且被赋值为 3.0。因此,2 * INT 的计算结果是 6.0。输出为:

2*INT = 6.00

解答 :

a = 5 b = 6

2*INT = 6.00

相关推荐
楚枫默寒13 小时前
Linux 编辑文件后自动添加修改日期
linux·运维·bash
集成显卡14 小时前
Rust实战七 |基于带 colored 颜色文字控制台的批量文件删除工具
开发语言·后端·rust
比昨天多敲两行15 小时前
linux 线程概念与控制
java·开发语言·jvm
huaweichenai15 小时前
php 根据每个类型的抽签范围实现抽签功能
开发语言·php
8Qi815 小时前
LeetCode 75:颜色分类(荷兰国旗问题)—— Java 题解 ✅
java·算法·leetcode·指针·排序
2601_9611940216 小时前
27考研刘晓艳单词pdf
linux·sql·ubuntu·华为·pdf·.net
codeejun16 小时前
每日一Go-73、云原生成本优化 —— 资源限制 & 指标驱动扩容
开发语言·云原生·golang
888CC++17 小时前
如何在 C 语言中进行程序调试?
前端·javascript·算法
就叫_这个吧17 小时前
Java注解、元注解、自定义注解定义及应用
java·开发语言·注解