数组3

变长数组(VLA)

变长数组不能改变大小,但可以使用变量指定数组的维度

 int quarters = 4;
 int regions = 5;
 double sales[regions][quarters];    // 一个变长数组(VLA)

使用变长数组时要先声明使用的变量:
int sum2d(int rows, int cols, int ar[rows][cols]); // ar是一个变长数组(VLA)
int sum2d(int ar[rows][cols], int rows, int cols); // 无效的顺序
而C99/C11标准规定,可以省略原型中的形参名,但是在这种情况下,必须要用星号来代替省略的维度:
int sum2d(int, int, int ar[][]); // ar是一个变长数组(VLA),省略了维度形参名
上代码:

 /*将数组中的元素相加*/
 int sum2d(int rows, int cols, int ar[rows][cols])/*将符号常量COLS替换成了变量cols*/
 {
 int r;
 int c;
 int tot = 0;

 for (r = 0; r < rows; r++)
      for (c = 0; c < cols; c++)
           tot += ar[r][c];
 return tot;
 }
 该函数可以处理任意大小的二维int数组

以变长数组作为形参的函数既可以处理传统C数组,也可以处理变长数组(该程序要求编译器支持变长数组特性)

 //vararr2d.c -- 使用变长数组的函数
 #include <stdio.h>
 #define ROWS 3
 #define COLS 4
 int sum2d(int rows, int cols, int ar[rows][cols]);
 int main(void)
 {
 int i, j;
 int rs = 3;
 int cs = 10;
 int junk[ROWS][COLS] = {
           { 2, 4, 6, 8 },
           { 3, 5, 7, 9 },
           { 12, 10, 8, 6 }
 };

 int morejunk[ROWS - 1][COLS + 2] = {
           { 20, 30, 40, 50, 60, 70 },
           { 5, 6, 7, 8, 9, 10 }
 };

 int varr[rs][cs];  // 变长数组(VLA)

 for (i = 0; i < rs; i++)
      for (j = 0; j < cs; j++)
           varr[i][j] = i * j + j;

 printf("3x4 array\n");
 printf("Sum of all elements = %d\n", sum2d(ROWS, COLS, junk));

 printf("2x6 array\n");
 printf("Sum of all elements = %d\n", sum2d(ROWS - 1, COLS + 2, morejunk));

 printf("3x10 VLA\n");
 printf("Sum of all elements = %d\n", sum2d(rs, cs, varr));

 return 0;
 }

 // 带变长数组形参的函数
 int sum2d(int rows, int cols, int ar[rows][cols])
 {
 int r;
 int c;
 int tot = 0;

 for (r = 0; r < rows; r++)
      for (c = 0; c < cols; c++)
           tot += ar[r][c];

 return tot;
 }

数组3

输出结果应为:

 3x4 array
 Sum of all elements = 80
 2x6 array
 Sum of all elements = 315
 3x10 VLA
 Sum of all elements = 270

复合字面量

字面量:除符号常量外的常量
对于数组,复合字面量类似数组初始化列表,前面是用括号括起来的类型名。
数组初始化:

 int diva[2] = {10, 20};

下面的复合字面量创建了一个和diva数据相同的匿名数组,也有两个int类型的值:

 (int [2]){10, 20} // 内含3个元素的复合字面量

注意,去掉声明中的数组名,留下的int[2]即是复合字面量的类型名。
初始化有数组名的数组时可以省略数组的大小,复合字面量也可以省略大小,编译器会自动计算数组当前的元素个数:

 (int []){50, 20, 90} // 内含3个元素的复合字面量

因为复合字面量是匿名的,所以不能先创建然后再使用,必须在创建的同时使用它。使用指针记录地址就是一种用法。上代码:

 int * pt1;
 pt1 = (int [2]) {10, 20};

与有数组名的数组类似,复合字面量的类型名也代表首元素的地址,所以可以把它赋给指向int的指针,然后便可以使用这个指针。例如,上述的*pt1是10,pt1[1]是20
还可以把复合字面量作为实际参数传递给带有匹配形式参数的函数:

 int sum(const int ar[], int n);
 ...
 int total3;
 total3 = sum((int []){4,4,4,5,5,5}, 6);

在此例中,第一个实参是内含6个int类型值的数组,和数组名类似,这同时也是该数组的首元素的地址。这种用法的好处是,把信息传入函数前不用先创建数组(典型用法)
以此类推,这种用法也应用于二维数组或多维数组,例如:

 int (*pt2)[4];    // 声明一个指向二维数组的指针,该数组内含2个数组元素,
              // 每个元素是内含4个int类型值的数组
 pt2 = (int [2][4]) { {1,2,3,-9}, {4,5,6,-8} };

当应用于实际代码中时:

 // flc.c -- 有趣的常量
 #include <stdio.h>
 #define COLS 4
 int sum2d(const int ar[][COLS], int rows);
 int sum(const int ar[], int n);
 int main(void)
 {
 int total1, total2, total3;
 int * pt1;
 int(*pt2)[COLS];

 pt1 = (int[2]) { 10, 20 };
 pt2 = (int[2][COLS]) { {1, 2, 3, -9}, { 4, 5, 6, -8 } };

 total1 = sum(pt1, 2);
 total2 = sum2d(pt2, 2);
 total3 = sum((int []){ 4, 4, 4, 5, 5, 5 }, 6);
 printf("total1 = %d\n", total1);
 printf("total2 = %d\n", total2);
 printf("total3 = %d\n", total3);

 return 0;
 }

 int sum(const int ar [], int n)
 {
 int i;
 int total = 0;

 for (i = 0; i < n; i++)
      total += ar[i];

 return total;
 }

 int sum2d(const int ar [][COLS], int rows)
 {
 int r;
 int c;
 int tot = 0;

 for (r = 0; r < rows; r++)
      for (c = 0; c < COLS; c++)
           tot += ar[r][c];

 return tot;
 }

该程序需要支持C99的编译器才能正常运行
复合字面量的使用
数组3

表示字符串和字符串组I/O

前情回顾:字符串是以空字符(\0)结尾的char类型数组
在程序中表示字符串:

 //  strings1.c
 #include <stdio.h>
 #define MSG "I am a symbolic string constant."
 #define MAXLENGTH 81
 int main(void)
 {
 char words[MAXLENGTH] = "I am a string in an array.";
 const char * pt1 = "Something is pointing at me.";
 puts("Here are some strings:");
 puts(MSG);
 puts(words);
 puts(pt1);
 words[8] = 'p';
 puts(words);

 return 0;
 }

puts函数也属于stdio.h系列的输入/输出函数,但puts函数只显示字符串,而且自动在显示的字符串末尾加上换行符。

显示字符串
数组3

上一篇:JZ-065-矩阵中的路径


下一篇:JZ13 机器人的运动范围