实验 4_C语言数组应用编程

一、实验目的

1. 能正确使用C语法规则定义、初始化、访问、输入/输出一维/二维数组

2. 能正确使用数组作为函数参数

3. 针对具体问题场景,能灵活用数组组织数据,应用、设计算法编程解决实际问题

二、实验过程

Task1:一维、二维数组的地址

源代码:

 1 #include <stdio.h>
 2 #define N 4
 3 #define M 2
 4 
 5 void test1() {
 6     int x[N] = {1, 9, 8, 4};          
 7     int i;
 8 
 9     // 输出数组x占用的内存字节数
10     printf("sizeof(x) = %d\n", sizeof(x));
11 
12     // 输出每个元素的地址、值 
13     for (i = 0; i < N; ++i)
14         printf("%p: %d\n", &x[i], x[i]);
15 
16     // 输出数组名x对应的值 
17     printf("x = %p\n", x); 
18 }
19 
20 void test2() {
21     int x[M][N] = {{1, 9, 8, 4}, {2, 0, 4, 9}};
22     int i, j;
23 
24     // 输出二维数组x占用的内存字节数
25     printf("sizeof(x) = %d\n", sizeof(x));
26 
27     // 输出每个元素的地址、值 
28     for (i = 0; i < M; ++i)
29         for (j = 0; j < N; ++j)
30             printf("%p: %d\n", &x[i][j], x[i][j]);
31     printf("\n");
32 
33     // 输出二维数组名x, 以及,x[0], x[1]的值
34     printf("x = %p\n", x);
35     printf("x[0] = %p\n", x[0]);
36     printf("x[1] = %p\n", x[1]);
37     printf("\n");
38 }
39 
40 int main() {
41     printf("测试1: int型一维数组\n");
42     test1();
43 
44     printf("\n测试2: int型二维数组\n");
45     test2();
46 
47     return 0;
48 }
task1.c

运行结果:

问题回答:

问题 1 : int 型一维数组 x ,在内存中是否是连续存放的?数组名 x 对应的值,和 &x[0] 是⼀样的吗?

答:是连续存放的。数组名 x 对应的值和数组的首地址 &x[0] 是⼀样的。

问题 2 : int 型⼆维数组 x ,在内存中是否是 " 按行连续存放 " 的?数组名 x 的值、x[0] 、 &x[0][0] ,其值,在字面上,是⼀样的吗? x[0] 和 x[1] 相差多少?你能猜测 / 推断出这个差值的意义吗?

答:int 型⼆维数组 x 在内存中是 " 按行连续存放 " 的。

x:表示二维数组的起始位置,即指向第一行的地址。x[0]:表示第一行的起始位置,即指向 x[0][0] 的地址。&x[0][0]:表示第一行第一列元素的地址。因此,从概念上讲,x 和 x[0]、&x[0][0] 在字面上是相同的,内容都是第一行第一个元素的地址。

x[0] 和 x[1]之间的差值是N * sizeof(int)(即在上面的示例中是 4 * sizeof(int),假设 sizeof(int) 是 4 字节,结果是 4*4=16 字节)。在内存中,第二行的起始地址距离第一行的起始地址相隔 N 个 int 类型的大小的字节。

这个距离表明了二维数组的行数和列数是如何在内存中布局的。具体来说,一个二维数组的行数在内存中是连续存放的,且每行的元素数量决定了后续行的起始地址。差值确保了数组能够被有效地按行索引和访问。

Task2:验证一维数组作为函数形参的用法

源代码:

 1 #include <stdio.h>
 2 #define N 100
 3 
 4 // 函数声明
 5 void input(int x[], int n);
 6 double compute(int x[], int n);
 7 
 8 int main() {
 9     int x[N];
10     int n, i;
11     double ans;
12 
13     while (printf("Enter n: "), scanf_s("%d", &n) != EOF) {
14         input(x, n);            // 函数调用
15         ans = compute(x, n);    // 函数调用
16         printf("ans = %.2f\n\n", ans);
17     }
18 
19     return 0;
20 }
21 
22 // 函数定义
23 void input(int x[], int n) {
24     int i;
25 
26     for (i = 0; i < n; ++i)
27         scanf_s("%d", &x[i]);
28 }
29 
30 // 函数定义
31 double compute(int x[], int n) {
32     int i, high, low;
33     double ans;
34 
35     high = low = x[0];
36     ans = 0;
37 
38     for (i = 0; i < n; ++i) {
39         ans += x[i];
40 
41         if (x[i] > high)
42             high = x[i];
43         else if (x[i] < low)
44             low = x[i];
45     }
46 
47     ans = (ans - high - low) / (n - 2);
48 
49     return ans;
50 }
task2.c

运行结果:

问题回答:

观察:⼀维数组作为形参时,其书写形式?实参的书写形式?

答:形参的书写形式:在函数声明或定义中,一维数组形参写作 int x[] ,表示传入一个整型数组。

实参的书写形式:调用函数时,直接传入数组名即可。例如:input(x, n); 这里 x 是数组名,表示数组在内存中首元素的地址。

问题:函数 input 的功能是?函数 compute 的功能是?

答:input 的功能是从标准输入读取 n 个整数,依次存入数组 x 中。函数 compute 的功能是计算数组 x 中所有元素的总和 ans,同时找出最大值 high 和最小值 low,然后去掉最大值和最小值再计算剩余元素的平均值,并返回这个平均数。

Task3:验证二维数组作为函数形参的用法

源代码:

 1 #include <stdio.h>
 2 #define N 100
 3 // 函数声明
 4 void output(int x[][N], int n);
 5 void init(int x[][N], int n, int value);
 6 int main() {
 7     int x[N][N];
 8     int n, value;
 9     while (printf("Enter n and value: "), scanf_s("%d%d", &n, &value) != EOF) {
10         init(x, n, value);  // 函数调用
11         output(x, n);
12         printf("\n");
13     }
14     return 0;
15 }
16 // 函数调用
17 // 函数定义
18 void output(int x[][N], int n) {
19     int i, j;
20     for (i = 0; i < n; ++i) {
21         for (j = 0; j < n; ++j)
22             printf("%d ", x[i][j]);
23         printf("\n");
24     }
25 }
26 // 函数定义
27 void init(int x[][N], int n, int value) {
28     int i, j;
29     for (i = 0; i < n; ++i)
30         for (j = 0; j < n; ++j)
31             x[i][j] = value;
32 }
task3.c

运行结果:

问题回答:

观察:两维数组作为函数形参时,形参的书写形式?实参的书写形式?

答:形参写法:函数形参声明时,对于二维数组,如 int x[][N],必须明确第二维的大小N,而第一维可以省略。实参写法:实参传递时就是普通的二维数组变量名,如x,不加任何维度大小。

问题1:两维数组作为函数形参时,哪⼀维的⼤⼩不能省略?

答:答:第二维的大小不能省略。因为C语言编译器需要知道每行的长度,从而正确计算地址偏移。第一维大小可以省略(通常用指向数组的指针代替)。

问题2:函数output功能是?函数init的功能是?

答:函数output功能是输出一个 n x n 的二维数组 x,逐行打印其中的元素。函数init的功能是初始化一个 n x n 的二维数组 x,将所有元素赋值为value

Task4:计算⼀组数据中值

源代码:

 1 #include <stdio.h>  
 2 #define N 100  
 3 
 4 // 函数声明  
 5 void input(int x[], int n);
 6 double median(int x[], int n);
 7 
 8 int main() {
 9     int x[N];
10     int n;
11     double ans;
12     while (printf("Enter n: "), scanf_s("%d", &n) != EOF) {
13         input(x, n);            // 读取数据  
14         ans = median(x, n);     // 计算中值  
15         printf("ans = %g\n\n", ans);
16     }
17     return 0;
18 }
19 
20 // 从键盘读入n个整数到数组x  
21 void input(int x[], int n) {
22     int i;
23     printf("Enter %d numbers: ", n);
24     for (i = 0; i < n; ++i) {
25         scanf_s("%d", &x[i]);
26     }
27 }
28 
29 // 计算中值,先对数组排序,再计算中位数  
30 double median(int x[], int n) {
31     int i, j, temp;
32     // 简单冒泡排序
33     for (i = 0; i < n - 1; ++i) {
34         for (j = 0; j < n - 1 - i; ++j) {
35             if (x[j] > x[j + 1]) {
36                 temp = x[j];
37                 x[j] = x[j + 1];
38                 x[j + 1] = temp;
39             }
40         }
41     }
42 
43     // 计算中值  
44     if (n % 2 == 1) {
45         // 奇数个数 - 中间那个数  
46         return x[n / 2];
47     }
48     else {
49         // 偶数个数 - 取中间两个数的均值  
50         return (x[n / 2 - 1] + x[n / 2]) / 2.0;
51     }
52 }
task4.c

运行结果:

 Task5:实现数值阵列处理

源代码:

 1 #include <stdio.h>  
 2 #define N 100  
 3 
 4 // 函数声明  
 5 void input(int x[][N], int n);
 6 void output(int x[][N], int n);
 7 void rotate_to_right(int x[][N], int n);  // 补充声明  
 8 
 9 int main() {
10     int x[N][N];
11     int n;
12     printf("Enter n: ");
13     scanf_s("%d", &n);
14 
15     input(x, n);
16 
17     printf("原始矩阵:\n");
18     output(x, n);
19 
20     rotate_to_right(x, n);  // 调用按列右移函数  
21 
22     printf("变换后矩阵:\n");
23     output(x, n);
24 
25     return 0;
26 }
27 
28 // 输入函数定义  
29 void input(int x[][N], int n) {
30     int i, j;
31     for (i = 0; i < n; ++i) {
32         for (j = 0; j < n; ++j)
33             scanf_s("%d", &x[i][j]);
34     }
35 }
36 
37 // 输出函数定义  
38 void output(int x[][N], int n) {
39     int i, j;
40     for (i = 0; i < n; ++i) {
41         for (j = 0; j < n; ++j)
42             printf("%4d", x[i][j]);
43         printf("\n");
44     }
45 }
46 
47 // rotate_to_right函数定义  
48 void rotate_to_right(int x[][N], int n) {
49     int i, j;
50     int last_col[N];
51 
52     // 先保存最右边一列  
53     for (i = 0; i < n; i++)
54         last_col[i] = x[i][n - 1];
55 
56     // 每列元素右移一列  
57     for (j = n - 1; j > 0; j--) {
58         for (i = 0; i < n; i++) {
59             x[i][j] = x[i][j - 1];
60         }
61     }
62 
63     // 最左边列赋值为保存的最右边列  
64     for (i = 0; i < n; i++) {
65         x[i][0] = last_col[i];
66     }
67 }
task5.c

运行结果:

 Task6:进制转换

源代码:

 1 #include <stdio.h>
 2 #define N 100
 3 
 4 void dec_to_n(int x, int n); // 函数声明
 5 
 6 int main() {
 7     int x;
 8     
 9     while (printf("输入十进制整数: "), scanf_s("%d", &x) != EOF) {
10         dec_to_n(x, 2);  // 函数调用: 把x转换成二进制输出
11         dec_to_n(x, 8);  // 函数调用: 把x转换成八进制输出
12         dec_to_n(x, 16); // 函数调用: 把x转换成十六进制输出
13         printf("\n");
14     }
15 
16     return 0;
17 }
18 
19 // 函数定义
20 // 功能: 把十进制数x转换成n进制,打印输出
21 void dec_to_n(int x, int n) {
22     char map[]= "0123456789ABCDEF"; //制作转换所需的字符表
23     char exchange[N]; //保存转换后的字符串  
24     int d, r; //商和余数
25     int cnt = 0; //计数余数的个数
26 
27     // 使用除法和取余法进行进制转换  
28     while (1) {
29         r = x % n; //计算余数
30         d = x / n; //计算商
31         exchange[cnt++] = map[r]; //一一映射关系
32 
33         if (d == 0)
34             break;
35 
36         x = d; //把商作为新的被除数
37     }
38 
39     // 把计算出来的余数逆序输出  
40     for (--cnt;cnt >= 0;--cnt) {
41         printf("%c", exchange[cnt]); //输出字符  
42     }
43 
44     printf("\n"); //在不同进制之间换行
45 }
task6.c

运行结果:

 三、实验心得

在使用AI辅助编程练习的过程中,需要学习如何prompt,可以输入更好的算法,以实现高质量的人机对话。

posted @ 2025-04-21 11:42  Meredith_GISer  阅读(79)  评论(0)    收藏  举报