作业一
数组练习
-
选择题
1.1、若有定义语句:int a[3][6]; ,按在内存中的存放顺序,a 数组的第10个元素是
a[0][4] B) a[1][3] C)a[0][3] D)a[1][4]
解析:
从 a[0][0] 开始,第一行有 6 个元素,分别是 a[0][0] 到 a[0][5],即第 1 到第 6 个元素。
接着从 a[1][0] 开始,第二行前 4 个元素是 a[1][0] 到 a[1][3],即第 7 到第 10 个元素。
所以,第 10 个元素是 a[1][3]
解答:
B
1.2、有数组 int a[5] = {10,20,30,40,50}, 以下表达式编译错误是____________。
A) a ++ ;
B) a[5] = 20 ;
C) a + 20 ;
D) (a-3, a[3]) ;
解析:
A) a++ ;
错误:a++ 是不合法的。
原因:在 C 语言中,数组名 a 是一个指向数组第一个元素的指针常量,它的值不可改变。也就是说,数组名 a 不能被自增,因为它是一个 常量指针,指向数组首地址,不能通过 ++ 操作改变。
B) a[5] = 20 ;
错误:虽然语法上没有问题,但会导致 数组越界 错误。
原因:a[5] 实际上是访问数组的第 6 个元素,而 a[5] 数组只有 5 个元素,索引范围是 a[0] 到 a[4]。因此,访问 a[5] 会导致 越界访问,尽管某些编译器可能不会报错,但这是一个逻辑错误。
C) a + 20 ;
正确:这个表达式不会编译错误。
原因:a + 20 是一个合法的指针运算。它将指针 a 偏移 20 个元素的位置,虽然这样做的结果可能是非法的地址访问,但仅仅是表达式本身不会导致编译错误。
D) (a-3, a[3]) ;
正确:这个表达式不会编译错误。
原因:这是一个逗号表达式,先计算 a-3(虽然结果无实际意义),然后计算 a[3],最终返回 a[3] 的值。语法上没有问题。
解答:
A
1.3、以下错误的定义语句是 _______
A)int x[][3] = {{0},{1},{1,2,3}};
B)int x[4][3] = {{1,2,3},{1,2,3},{1,2,3},{1,2,3}};
C)int x[4][] = {{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 x[4][3] = {{1,2,3},{1,2,3},{1,2,3},{1,2,3}};
正确:这是合法的定义。
原因:明确定义了 4 行 3 列的二维数组,并且每行都初始化了 3 个元素,符合数组初始化规则。
C) int x[4][] = {{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] 列的二维数组中。结果是 x[0][0] = 1, x[0][1] = 2, x[0][2] = 3, x[1][0] = 4,其余的未初始化元素将被自动填充为 0。因此,这个定义也是合法的。
解答:
C
1.4、设int i,x[3][3]={1,2,3,4,5,6,7,8,9};则下面语句
for(i=0;i<3;i++)
printf(″%d, ″,x[i][2-i]);
的输出结果是
A)1, 4, 7 B)1, 5, 9 C)3, 6, 9 D)3, 5, 7
解析:
这里 x[i][2-i] 表示:
当 i = 0 时,x[0][2-0] = x[0][2] = 3
当 i = 1 时,x[1][2-1] = x[1][1] = 5
当 i = 2 时,x[2][2-2] = x[2][0] = 7
解答:
D
1.5、表达式“sizeof(int [1][2])/sizeof(int)”的值为_____。
A) 2 B) 3 C) 4 D) 5
解析:
sizeof(int [1][2]):
这个数组包含 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;s[i]!=0;i++)
if(s[i]>='0'&&s[i]<='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 (s[i] >= '0' && s[i] <= '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,表示数组的第一个元素 s[0],即字符 'w'。
表达式 *s + 2:
*s 取的是 s[0],即字符 'w'。
'w' 在 ASCII 码中的值是 119。
*s + 2 相当于 119 + 2 = 121,ASCII 码值 121 对应的字符是 'y'。
printf("%c\n", *s + 2); 输出的就是字符 'y'。
解答:
C
1.8 数组 int a[5] = {10, 20, 30, 40,50}, 有以下语句,其输出_______
printf(“%d\n”, *(&a +1) );
A) 20 B) 30 C) 随机值 D)编译报错
解析:
&a 的含义:
&a 是 数组 a 的地址,它的类型是 int (*)[5],即指向一个大小为 5 的整型数组的指针。
注意,这与 a 的地址(指向数组第一个元素 a[0] 的地址)是不同的。a 作为数组名时相当于 &a[0],是一个指向第一个元素的指针,而 &a 是整个数组的地址。
&a + 1 的含义:
&a + 1:这个表达式实际上是将 &a (数组 a 的地址)偏移一个数组的大小。因为 &a 是一个指向整个数组的指针,偏移 1 意味着它指向了数组 a 之后的地址。
也就是说,&a + 1 实际上指向的是数组 a[5] 后面的内存位置。
*( &a + 1 ) 的含义:
*( &a + 1 ) 试图 解引用 偏移后的地址。由于 &a + 1 指向数组 a 之外的内存,这意味着该表达式取出的值是数组 a 之后的内存中的内容。
这里访问的是超出数组范围的内存空间,会导致未定义行为。因此,输出的值是 随机的,也就是不可预测的。
解答:
C
1.9 有以下程序
# include <stdio.h>
int main()
{ int s[12]={1,2,3,4,4,3,2,1,1,1,2,3}, c[5]={0,0,0,0,0}, i ;
for(i=0;i<12;i++) c[s[i]]++ ;
for(i=1;i<5;i++) printf(“%d,”,c[i]); printf(“\n”);
}
A) 4 ,3, 3, 2 B) 2 , 3, 4, 4
C) 1, 2, 3 ,4 D ) 4, 4, 2 ,3
解析:
数组 s[12] 的初始化为:{1, 2, 3, 4, 4, 3, 2, 1, 1, 1, 2, 3}。
这个数组包含 12 个元素。
数组 c[5] 的初始化为:{0, 0, 0, 0, 0}。
这是一个用于统计出现次数的数组,c[i] 表示整数 i 在数组 s 中出现的次数。
for 循环统计元素出现次数:
c[s[i]]++ 根据数组 s[i] 的值,更新数组 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,", c[i]);
该循环会打印数组 c[1] 到 c[4] 的值,也就是 4, 3, 3, 2。
解答:
A
1.10 有数组 int a[3][4] = {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 代表 指向第一行的指针,也就是 a[0],即地址 &a[0][0],指向的是第一个元素 10。
*a + 2:
*a 是 a[0] 的首地址,即 &a[0][0],加上 2 就是指向 a[0][2],也就是 30 的地址。
*(*a + 2):
这是对 a[0][2] 解引用,结果是 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++)
{n[i]=n[i-1]*3+1;
printf(“%d”,n[i]);}
}
程序运行后输出结果是 __________
解析:
当 i = 1:
n[1] = n[0] * 3 + 1 = 0 * 3 + 1 = 1
输出:1
当 i = 2:
n[2] = n[1] * 3 + 1 = 1 * 3 + 1 = 4
输出:4
当 i = 3:
n[3] = n[2] * 3 + 1 = 4 * 3 + 1 = 13
输出:13
当 i = 4:
n[4] = n[3] * 3 + 1 = 13 * 3 + 1 = 40
输出:40
解答:
141340
2.2、执行以下程序的输出结果是_ .
#include <stdio.h>
int main()
{ int i,n[4]={1,0,0,0};
for(i=1;i<=3;i++)
{ n[i]=n[i-1]*2+1; printf("%d",n[i]); }
}
解析:
当 i = 1:
n[1] = n[0] * 2 + 1 = 1 * 2 + 1 = 3
输出:3
当 i = 2:
n[2] = n[1] * 2 + 1 = 3 * 2 + 1 = 7
输出:7
当 i = 3:
n[3] = n[2] * 2 + 1 = 7 * 2 + 1 = 15
输出:15
解答:
3715
2.3、下面程序运行的结果为_________。
main()
{
int x[5],i;
x[0] = 1;x[1] = 2;
for(i = 2;i<5;i++) x[i] = x[i-1] + x[i-2];
for(i = 2;i<5;i++) printf(“%d”,x[i]);
}
解析:
i = 2:
x[2] = x[1] + x[0] = 2 + 1 = 3
当 i = 3:
x[3] = x[2] + x[1] = 3 + 2 = 5
当 i = 4:
x[4] = x[3] + x[2] = 5 + 3 = 8
数组 x 的最终内容:
x[0] = 1
x[1] = 2
x[2] = 3
x[3] = 5
x[4] = 8
第二 for 循环:
再次循环从 i = 2 到 i < 5,输出 x[2], x[3], x[4] 的值。
输出: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] = arr[10 % 5] = arr[0]
输出:1
当 i = 2:
arr[(start + i) % 5] = arr[(10 + 2) % 5] = arr[12 % 5] = arr[2]
输出:5
当 i = 4:
arr[(start + i) % 5] = arr[(10 + 4) % 5] = arr[14 % 5] = arr[4]
输出:2
当 i = 6:
arr[(start + i) % 5] = arr[(10 + 6) % 5] = arr[16 % 5] = arr[1]
输出: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",a[j]);
}
}
解析:
当 i = 1:
j = 5 - 1 = 4
输出 a[4] = 5。
当 i = 2:
j = 5 - 2 = 3
输出 a[3] = 4。
当 i = 3:
j = 5 - 3 = 2
输出 a[2] = 8。
当 i = 4:
j = 5 - 4 = 1
输出 a[1] = 2。
当 i = 5:
j = 5 - 5 = 0
输出 a[0] = 0。
解答:
5 4 8 2 0
2.6有以下程序
#include <stdio.h>
int main()
{ int n[2],i,j;
for(i=0;i<2;i++) n[i]=0; for(i=0;i<2;i++)
for(j=0;j<2;j++) n[j]=n[i]+1;
printf(“%d\n”,n[1]);
}
程序运行后的输出结果是 【】
解析:
第一次for循环作用是对数组进行初始化全部赋值为0
第二个双层for循环外层是控制次数
第一次i=0时
j=0
n[0]=n[0]+1=0+1=1
j=1
n[1]=n[0]+1=1+1=2
第二次i=1时
j=0
n[0]=n[1]+1=2+1=3
j=1
n[1]=n[1]+1=2+1=3
输出n[1]为3
解答:
3
3、编程题
3.1、 一个班10个学生的成绩,存放在一个一维数组中,要求找出其中成绩最高的学生的成绩和该生的序号。试编程。(试着用下标法和地址法两种方法表示数组)
代码解答:
下标法:
#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;
}
地址法:
#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门课程,要求输入全部学生的各门课程成绩,然后输出各门课程的平均成绩,并按照各个学生的平均成绩排序(成绩最高的学生排在数组最前面,最低学生排在数组最后面的行) (试着用下标法和地址法两种方法表示数组)。
代码解答:
下标法:
#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;
}
地址法:
#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,a[10],*p;
A) p=a+2; B) p=a[5];
C) p=a[2]+2; D) p=&(i+2);
解析:
A) p = a + 2;
这是合法的。a 是一个整型数组,a + 2 表示指向数组中第 3 个元素(索引为 2)的指针。p 可以正确地指向这个元素。
B) p = a[5];
这是不合法的。a[5] 表示数组中第 6 个元素的值(类型为 int),而 p 是一个整型指针,不能直接赋值一个 int 值。
C) p = a[2] + 2;
这是不合法的。a[2] 是数组中第 3 个元素的值(类型为 int),而 p 是指针,不能直接将一个 int 值加 2 后赋值给 p。
D) p = &(i + 2);
这是不合法的。&(i + 2) 表示 i + 2 的地址,但是 i + 2 是一个临时计算的值,不能取得地址。
解答:
A
1.2、有以下程序
main()
{
int a[3][3],*p,i;
p=&a[0][0];
for(i=0;i<9;i++)
p[i]=i;
for(i=0;i<3;i++)
printf("%d ",a[1][i]);
}
程序运行后的输出结果是 ____________
A)0 1 2
B)1 2 3
C)2 3 4
D)3 4 5
解析:
a[0][0] = 0
a[0][1] = 1
a[0][2] = 2
a[1][0] = 3
a[1][1] = 4
a[1][2] = 5
a[2][0] = 6
a[2][1] = 7
a[2][2] = 8
这里输出的是数组 a 的第二行,即 a[1][0]、a[1][1] 和 a[1][2],对应的值是 3、4 和 5。
解答:
D
1.3、有以下程序
int main()
{ int a[3][2]={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",a[i][j]);
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,将其存储到 a[0][0]。
当 i = 1 时,输入 2,将其存储到 a[1][0]。
因为循环只运行了 2 次,所以 a[2] 不会被修改。
对于 i = 0,a[0] = {1, 0} 输出 1 0
对于 i = 1,a[1] = {2, 0} 输出 2 0
对于 i = 2,a[2] = {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 b[4]={'a','b','c','d'}, *p=b;
point(p); printf("%c\n",*p);
}
程序运行后的输出结果是 __________
A)a B)b C)c D)d
解析:
当调用
point(p);
时,传递的是p
的副本。因此,原始指针p
在main
函数中的值仍然指向字符数组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 会指向 m[2],也就是 6。
*(k + 2) 的值为 6。
结果: 是 6。
B) k + 2
k + 2 是指针运算,它会返回指向 m[2] 的地址。
这个表达式的值是指针,不是 6。
结果: 不是 6。
C) *k + 2
*k 是 m[0],即 2。
*k + 2 的值为 2 + 2 = 4。
结果: 不是 6。
D) *k += 2
*k 是 m[0],即 2。这个表达式会将 m[0] 的值更新为 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 x[10],*p=x;,以下能给数组 x 下标为 6 的元素读入数 据的正确语句是
A)scanf("%f",&x[6]); B)scanf("%lf",*(x+6));
C)scanf("%lf",p+6); D)scanf("%lf",p[6]);
解析:
A) scanf("%f", &x[6]);
%f 是用于读取 float 类型的格式符,而 x[6] 是 double 类型的。
这个语句是错误的,因为格式符与变量类型不匹配。
不正确。
B) scanf("%lf", *(x + 6));
*(x + 6) 表示访问 x[6] 的值,但这里不应该使用解引用操作符 *。
正确的方式是使用 & 来获取地址。
这个语句是错误的。
不正确。
C) scanf("%lf", p + 6);
p + 6 是指向 x[6] 的指针,而 %lf 是用于读取 double 类型的格式符。
这个语句是正确的,因为它可以直接将 x[6] 的地址传递给 scanf。
正确。
D) scanf("%lf", p[6]);
p[6] 等价于 *(p + 6),表示访问 x[6] 的值,而不是地址。
因此,这个语句也是错误的,因为它尝试将一个值传递给 scanf,而 scanf 需要一个地址。
不正确。
解答:
C
1.10、若有定义语句:char s[3][10], (*k)[3], *p; ,则以下赋值语句正确的是____
A)p=s; B)p=s[0]; C)p=k; D)k=s;
解析:
A) p = s;
s 是 char 类型的二维数组,代表 char (*)[10](指向包含 10 个字符的数组的指针)。
p 是 char *,无法直接赋值。
不正确。
B) p = s[0];
s[0] 是指向 s 的第一行的指针,类型是 char *。
这与 p 的类型相匹配,因此这个赋值是有效的。
正确。
C) p = k;
k 的类型是 char (*)[3],指向包含 3 个字符的数组。
p 的类型是 char *,这两个类型不兼容。
不正确。
D) k = s;
s 的类型是 char (*)[10](指向包含 10 个字符的数组的指针),与 k 的类型不匹配。
不正确。
解答:
B
1.11、有定义语句:int *p[4]; 以下选项中与此语句等价的是
A)int p[4]; B)int **p; C)int *(p[4]); D)int (*p)[4];
解析:
int *p[4]; 定义了一个包含 4 个元素的数组 p,每个元素都是指向 int 的指针。也就是说,p 是一个指针数组,其中每个元素都指向一个 int 类型的值。
A) int p[4];
这定义了一个包含 4 个 int 类型元素的数组。与 int *p[4]; 不相同。
不等价。
B) int **p;
这定义了一个指向指针的指针,表示一个指向 int * 类型的指针。与 int *p[4]; 不相同。
不等价。
C) int *(p[4]);
这与 int *p[4]; 等价,因为它同样定义了一个包含 4 个 int * 类型元素的数组(虽然书写方式不同,但意义相同)。
等价。
D) int (*p)[4];
这定义了一个指向包含 4 个 int 元素的数组的指针,和 int *p[4]; 不同。
不等价。
解答:
C
1.12、若有定义语句:int a[4][10], *p, *q[4]; 且 0≤i<4,则错误的赋值 是
A)p=a B)q[i]=a[i] C)p=a[i] D)p=&a[2][1]
解析:
选项A:p = a
a 是一个二维数组 int a[4][10],在 C 语言中,a 的类型是 int (*)[10](指向包含 10 个整数的一维数组的指针)。
p 是一个 int * 类型的指针。
在这种情况下,p = a 的赋值是 不合法 的,因为:
a 是一个指向一维数组的指针,不能直接赋值给一个指向单个 int 的指针 p。这种赋值会导致类型不匹配。
正确的赋值应该是 p = &a[0][0],这样 p 才会指向数组的第一个元素。
解答:
A
1.13、若有以下定义
int x[10],*pt=x;
则对 x 数组元素的正确应用是
A)*&x[10] B)*(x+3)
3C)*(pt+10) D)pt+3
解析:
A)*&x[10]
x[10] 超出了数组的有效范围(合法索引为 0 到 9),因此访问 x[10] 是不合法的。
结果:不合法
B)*(x + 3)
x + 3 指向数组 x 的第四个元素(索引为 3)。
*(x + 3) 访问这个元素的值。
结果:合法,返回 x[3] 的值。
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=&a[3];
--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。
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
指针 p 初始化为指向 a[3],即 p 的值为 &a[3](地址值指向元素 4)。
执行 --p;,指针 p 现在指向 a[2],即元素值 3。
y = *p; 解引用 p 得到 a[2] 的值,赋值给 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 s[3][10], (*k)[3], *p;,则以下赋值语句正确的是 A)p=s; B)p=k; C)p=s[0]; D)k=s;
解析:
A) p = s;
s 是 char 类型的二维数组,代表 char (*)[10](指向包含 10 个字符的数组的指针)。
p 是 char *,无法直接赋值。
不正确。
C) p = s[0];
s[0] 是指向 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 a[5]={2,4,6,8,10}, *p;
p=a+2;
printf(“%d”,*p++);
}
解析:
数组初始化:
int a[5] = {2, 4, 6, 8, 10};:数组 a 被初始化为 2, 4, 6, 8, 10。
指针赋值:
p = a + 2;:指针 p 指向数组 a 的第三个元素(a[2]),即 6。
打印输出:
printf("%d", *p++);:
*p 取出 p 指向的值(即 6)。
p++ 后缀自增,指针 p 将指向下一个元素(a[3],值为 8)。
因此,输出 6。
解答:
6
2.2、以下程序段的定义语句中,x[1]的初值是_____,程序运行后输出的内容是_______
#include<stdio.h>
main()
{ int x[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},*p[4],i;
for(i=0;i<4;i++)
{ p[i]=&x[2*i+1]; printf(“%d ”,p[i][0]);
}
printf(“\n”);
}
解析:
数组 x 的初始化:
x 被初始化为 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16。
x[1] 的初值:
因此,x[1] 的初值是 2。
在 for 循环中,指针 p[i] 被赋值为 &x[2*i + 1]:
当 i = 0:
p[0] = &x[2*0 + 1] = &x[1],此时 p[0] 指向 x[1](值为 2)。
输出 p[0][0],即 *p[0],结果为 2。
当 i = 1:
p[1] = &x[2*1 + 1] = &x[3],此时 p[1] 指向 x[3](值为 4)。
输出 p[1][0],即 *p[1],结果为 4。
当 i = 2:
p[2] = &x[2*2 + 1] = &x[5],此时 p[2] 指向 x[5](值为 6)。
输出 p[2][0],即 *p[2],结果为 6。
当 i = 3:
p[3] = &x[2*3 + 1] = &x[7],此时 p[3] 指向 x[7](值为 8)。
输出 p[3][0],即 *p[3],结果为 8。
解答:
2 2468
2.3 以下程序段的输出结果是( )
#include <sthio.h>
mian()
{ char *ch[4]={“red”,”green”,”blue”}; int i=0;
while(ch[i]);
{ putchar(ch[i][0]; i++; }
}
解析:
字符指针数组 ch:
char *ch[4] = {"red", "green", "blue", NULL}; 这是一个字符指针数组,存储了三个字符串和一个 NULL 指针,用于标识数组的结束。
while (ch[i]) 循环:
循环的条件是 ch[i],它会检查 ch[i] 是否为 NULL。如果不是,则继续执行循环。
输出 putchar(ch[i][0]):
ch[i][0] 获取字符串 ch[i] 的第一个字符。
对于字符串数组中的每个字符串,输出其首字符:
当 i = 0 时,ch[0] 是 "red",输出 r。
当 i = 1 时,ch[1] 是 "green",输出 g。
当 i = 2 时,ch[2] 是 "blue",输出 b。
当 i = 3 时,ch[3] 是 NULL,循环结束。
解答:
rgb
2.4、以下程序的功能是:借助指针变量找出数组元素中最大值所在的位置并输出该最大值。 请在输出语句中填写代表最大值的输出项。
#include <stdio.h>
int main()
{ int a[10], *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 a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
解析:
数组定义:
int a[5] = {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 结果是一个指向 int[5] 的指针,因此在进行强制类型转换后,ptr 实际指向的是 a 数组之后的第一个 int(即 a[5])。
打印输出:
*(a + 1):
这个表达式指向 a 数组的第二个元素,值是 2。
*(ptr - 1):
ptr - 1 实际上是指向 a[4](数组的最后一个元素),值是 5。
解答:
2,5
2.6 以下程序的功能是:借助指针变量找出数组元素中最大值所在的位置并输出该最大值。 请在输出语句中填写代表最大值的输出项。
#include <stdio.h>
int main( )
{ int a[10], *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个数
代码解答:
#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 a[4];
}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 name[9];
int age;
};
struct person class[10] = {“John”,17,”Paul”,19,”Mary”,18,”adam”,16};
A) printf(“%c\n”,class[3].name);
B) printf(“%c\n”,class[3].name[1]);
C) printf(“%c\n”,class[2].name[1]);
D) printf(“%c\n”,class[2].name[0]);
解析:
A) printf(“%c\n”,class[3].name);
这将尝试打印 class[3].name,这是一个字符串(字符数组),会导致类型不匹配错误。
B) printf(“%c\n”,class[3].name[1]);
class[3].name 对应的字符串是 "adam",name[1] 是 'd',因此不会打印出 M。
C) printf(“%c\n”,class[2].name[1]);
class[2].name 对应的字符串是 "Mary",name[1] 是 'a',因此不会打印出 M。
D) printf(“%c\n”,class[2].name[0]);
class[2].name 对应的字符串是 "Mary",name[0] 是 'M',所以这条语句将打印出字母 M。
解答 :
D
1.6、若有如下定义:
struct person
{
int id;
char name[10];
}per,*s = &per;
则以下对结构体成员的引用中错误的是____________。
A) per.name B) s->name[0]
C) (*per).name[8] D) (*s).id
解析:
A) per.name
这是一个正确的引用,直接访问 per 的 name 成员。
B) s->name[0]
这是一个正确的引用,使用箭头运算符(->)访问指针 s 指向的结构体的 name 成员。
C) (*per).name[8]
这是错误的引用。这里的 per 是一个结构体变量,而不是指针,因此不能使用解引用操作符 *。正确的写法应为 (*s).name[8] 或 s->name[8]。
D) (*s).id
这是一个正确的引用,使用解引用操作符访问指针 s 指向的结构体的 id 成员。
解答 :
C
1.7、下面程序的运行结构是____________。
main()
{
struct cmplx{int x;
int y;
}cnum[2] = {1,3,2,7};
printf(“%d\n”,cnum[0].y/cnum[0].x*cnum[1].x);
}
A)0 B)1 C)3 D)6
解析:
结构体初始化:
cnum[0] 初始化为 {1, 3},即 cnum[0].x = 1 和 cnum[0].y = 3。
cnum[1] 初始化为 {2, 7},即 cnum[1].x = 2 和 cnum[1].y = 7。
计算表达式:
首先计算 cnum[0].y / cnum[0].x:
cnum[0].y/cnum[0].x=3/1=3
cnum[0].y/cnum[0].x=3/1=3
然后乘以 cnum[1].x:
3∗cnum[1].x=3∗2=6
3∗cnum[1].x=3∗2=6
输出结果:
程序输出 6。
解答 :
D
1.8、若有以下定义和语句:
struct student
{
int age;
int num;
};
struct student stu[3] = {{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 不是有效的表达式。结构体数组的成员必须通过索引来访问。例如,应该使用 stu[0].age 来获取第一个结构体的 age 成员的地址
解答 :
D
1.9、设有以下定义和语句,以下引用形式不合法的是____________。
struct s
{
int il;
struct s *i2;
char *i0;
};
static struct s a[3] = {2,&a[1],'\0',4,&a[2], ‘\0’ , 6 ,&a[1], ‘\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 s[3] = {{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 指向 s[0],执行 ++p 后,p 指向 s[1]。
p->m 是 s[1].m,即 &b,其值为 2。
值为 2。
B) *(p++)->m
p 指向 s[0],首先解引用 p,p->m 是 s[0].m,即 &a,其值为 1。
然后 p++ 会使 p 指向 s[1]。所以这个表达式返回的是 *(&a) 的值,结果为 1。
值为 1。
C) (*p).m
此时 p 指向 s[0],(*p).m 是 s[0].m,即 &a,值为 1。
值为 1。
D) *(++p)->m
p 指向 s[0],执行 ++p 后,p 指向 s[1]。
*(p->m) 是 *(s[1].m),即 *(&b),值为 2。
值为 2。
解答 :
AD
1.12、若有以下说明和语句,则对pup中sex域的正确引用方式是____________
struct pupil
{
char name[20];
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 dt[4] = {10,20,30,40};
struct stu a[4] = {50,&dt[0],60,&dt[1],70,&dt[2],80,&dt[3]};
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 最初指向 a[0],即 x = 50。
++p->x 会先将 p->x(即 a[0].x)加 1,然后输出 51。
此时 a[0].x 的值变为 51。
输出: 51
第二行: printf("%d", (++p)->x);
++p 将 p 移动到 a[1],即 x = 60。
输出 60。
输出: 60
第三行: printf("%d", ++(*p->y));
此时 p 仍然指向 a[1]。
p->y 指向 dt[1],即 y = 20。
++(*p->y) 将 dt[1] 的值加 1,变为 21。
输出: 21
解答 :
C
1.14、若有以下说明和语句,则下面表达式中值为1002的是____________。
struct student
{
int age;
int num;
};
struct student stu[3] = {{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 的当前值(stu[0]),然后将 p 指向 stu[1]。
p->num 为 20(stu[0].num),所以输出是 20,不是 1002。
B) (p++)->age
同样,p++ 先使用 stu[0],然后将 p 指向 stu[1]。
p->age 为 1001(stu[0].age),所以输出是 1001,不是 1002。
C) (*p).num
此时 p 仍然指向 stu[0],所以 (*p).num 为 20,不是 1002。
D) (*++p).age
++p 将 p 移动到 stu[1]。
(*p).age 为 1002(stu[1].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 a[3] = {1,&a[1],2,&a[2],3,&a[0]},*ptr;
ptr = &a[1];
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 指向 a[1],所以返回值为 2,然后 ptr 移动到下一个元素(指向 a[2])。所以返回值不是 3。
C) (ptr++)->il
这个表达式与选项 B 类似,首先返回 ptr->il 的值,即 2,然后再进行指针自增。返回值不是 3。
D) ++ptr->il
这个表达式会首先对 ptr->il 进行自增,ptr 指向 a[1],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 ch[2];
}a;
main( )
{
a.ch[0] = 13;
a.ch[1] = '0';
printf(“%d\n”,a.i);
}
A) 12301 B)4813 C) 208 D) 209
解析:
内存布局分析
a.ch[0] 被赋值为 13,其十六进制表示为 0x0D。
a.ch[1] 被赋值为字符 '0',其 ASCII 值为 48,十六进制表示为 0x30。
联合体的内存结构通常是按照小端字节序(little-endian)存储的:
a.ch[0](低位字节)存储在地址的低位,即 0x0D。
a.ch[1](高位字节)存储在地址的高位,即 0x30。
计算 a.i
在小端字节序下,a.i 的内存布局如下:
低位(ch[0]):0x0D (13)
高位(ch[1]):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 a[2];
int b[4];
char c[8];
}TY;
TY our;
main()
{
printf(“%d\n”,sizeof(our));
}
A) 32 B)16 C) 8 D)24
解析:
在这个程序中,TY 是一个 union,其成员包括:
一个包含 2 个 long 类型元素的数组 a[2]。
一个包含 4 个 int 类型元素的数组 b[4]。
一个包含 8 个 char 类型元素的数组 c[8]。
union 的大小由其最大成员决定。在 64 位操作系统中:
一个 long 类型通常占用 8 字节,因此 a[2] 占用 16 字节。
一个 int 类型通常占用 4 字节,因此 b[4] 占用 16 字节。
一个 char 类型占用 1 字节,因此 c[8] 占用 8 字节。
因此,union TY 的大小取决于其最大成员 a[2],即 16 字节。因此,sizeof(our) 将返回 16。
解答 :
B
二、填空题
2.1、有结构体
struct ST
{
int a;
float b;
sturct ST *c;
double x[3];
}st1;
请填空,完成以下对数组s的定义,使其每个元素均为上述结构体类型。
____________ s[10];
解析:
要定义一个包含结构体 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。
2. 表达式 (*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;
} s[4],*p;
main()
{
int n = 1,i;
printf(“\n”);
for(i = 0;i < 4;i++)
{
s[i].a = n;
s[i].b = &s[i].a;
n = n+2;
}
p = &s[0];
p++;
printf(“%d,%d\n”,(++p)->a, (p++)->a ) ;
}
解析:
在 for 循环中:
s[0].a = 1
s[1].a = 3
s[2].a = 5
s[3].a = 7
对应的指针 b 均指向各自的 a 成员。 ++p 使 p 指向 s[2],然后访问 s[2].a 的值,即 5。
(p++)->a 先访问当前 p 指向的 s[2] 的 a 的值(即 5),然后 p 自增到 s[3]。
因此,printf 的输出将是:
第一个 %d 输出 5(来自 s[2].a)。
第二个 %d 输出 5(来自 s[2].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->c[1]);
}
解析:
第一个 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->c[1] 指向字符串 "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 s[4];
union ks *p;
main( )
{
int n = 1,i;
printf(“\n”);
for(i = 0;i < 4;i++)
{
s[i].a = n;
s[i].b = s[i].a + i;
n = n+2;
}
p = &s[2];
printf(“%d,”,p++->a);
printf(“%d”,++p->a);
}
解析:
联合体数组初始化:
s[0]:
s[0].a = 1
s[0].b = 1 + 0 = 1(s[0].b 取值是 1,覆盖了 s[0].a)
s[1]:
s[1].a = 3
s[1].b = 3 + 1 = 4(s[1].b 取值是 4,覆盖了 s[1].a)
s[2]:
s[2].a = 5
s[2].b = 5 + 2 = 7(s[2].b 取值是 7,覆盖了 s[2].a)
s[3]:
s[3].a = 7
s[3].b = 7 + 3 = 10(s[3].b 取值是 10,覆盖了 s[3].a)
最终状态:
s[0]:a = 1, b = 1
s[1]:a = 4, b = 4
s[2]:a = 7, b = 7
s[3]:a = 10, b = 10
指针操作:
p = &s[2];,指向 s[2](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,因此输出 name[2],对应的字符串为 "dime"。
name[(int)money2]:(int)money2 的值是 5,因此输出 name[5],对应的字符串为 "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
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » 国庆练习(Day24)
发表评论 取消回复