关键字:static
运算符:&、*(一元)
如何创建并初始化数组
指针、指针和数组的关系
编写处理数组的函数
二维数组
目录
10.1 数组
10.1.1 初始化数组
/* day_mon1.c -- prints the days for each month */
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
int index;
for (index = 0; index < MONTHS; index++)
printf("Month %d has %2d days.\n", index +1,
days[index]);
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang day_mon1.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
Month 1 has 31 days.
Month 2 has 28 days.
Month 3 has 31 days.
Month 4 has 30 days.
Month 5 has 31 days.
Month 6 has 30 days.
Month 7 has 31 days.
Month 8 has 31 days.
Month 9 has 30 days.
Month 10 has 31 days.
Month 11 has 30 days.
Month 12 has 31 days.
/* no_data.c -- uninitialized array */
#include <stdio.h>
#define SIZE 4
int main(void)
{
int no_data[SIZE]; /* uninitialized array */
int i;
printf("%2s%14s\n",
"i", "no_data[i]");
for (i = 0; i < SIZE; i++)
printf("%2d%14d\n", i, no_data[i]);
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang no_data.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
i no_data[i]
0 0
1 0
2 0
3 0
/* some_data.c -- partially initialized array */
#include <stdio.h>
#define SIZE 4
int main(void)
{
int some_data[SIZE] = {1492, 1066};
int i;
printf("%2s%14s\n",
"i", "some_data[i]");
for (i = 0; i < SIZE; i++)
printf("%2d%14d\n", i, some_data[i]);
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang some_data.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
i some_data[i]
0 1492
1 1066
2 0
3 0
/* day_mon2.c -- letting the compiler count elements */
#include <stdio.h>
int main(void)
{
const int days[] = {31,28,31,30,31,30,31,31,30,31};
//编译器根据初始化列表中的项数来确定数组的大小
int index;
for (index = 0; index < sizeof days / sizeof days[0]; index++)
//计算机计算数组的大小,以字节为单位
printf("Month %2d has %d days.\n", index +1,
days[index]);
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang day_mon2.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
Month 1 has 31 days.
Month 2 has 28 days.
Month 3 has 31 days.
Month 4 has 30 days.
Month 5 has 31 days.
Month 6 has 30 days.
Month 7 has 31 days.
Month 8 has 31 days.
Month 9 has 30 days.
Month 10 has 31 days.
//自动计数的弊端,无法察觉初始化列表中的项数有误。
10.1.2 指定初始化器(C99)
// designate.c -- use designated initializers
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28, [4] = 31,30,31};
//C99指定初始化器(designated initializer)
//后面的值被用于初始化指定元素后面的元素
int i;
for (i = 0; i < MONTHS; i++)
printf("%2d %d\n", i + 1, days[i]);
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang designate.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
1 31
2 28
3 0
4 0
5 31
6 30
7 31
8 0
9 0
10 0
11 0
12 0
10.1.3 给数组元素赋值
#define SIZE 5
int main(void)
{
int oxen[SIZE] = {5,3,2,8} //没问题
int yaks[SIZE];
yaks = oxen; //不允许
yakes[SIZE] = oxen[SIZE]; //数组下标越界
yakes[SIZE] = {5,3,2,8} //除初始化以外也不允许使用花括号列表的形式赋值
}
10.1.4 数组边界
// bounds.c -- exceed the bounds of an array
#include <stdio.h>
#define SIZE 4
int main(void)
{
int value1 = 44;
int arr[SIZE];
int value2 = 88;
int i;
printf("value1 = %d, value2 = %d\n", value1, value2);
for (i = -1; i <= SIZE; i++)
arr[i] = 2 * i + 1;
for (i = -1; i < 7; i++)
printf("%2d %d\n", i , arr[i]);
printf("value1 = %d, value2 = %d\n", value1, value2);
//printf("address of arr[-1]: %p\n", &arr[-1]);
printf("address of arr[4]: %p\n", &arr[4]);
printf("address of value1: %p\n", &value1);
printf("address of value2: %p\n", &value2);
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang bounds.c
bounds.c:19:41: warning: array index -1 is before the beginning of the array [-Warray-bounds]
printf("address of arr[-1]: %p\n", &arr[-1]);
^ ~~
bounds.c:7:5: note: array 'arr' declared here
int arr[SIZE];
^
1 warning generated.
[wlsh@wlsh-MacbookPro] ch10$ clang bounds.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
value1 = 44, value2 = 88
-1 -1
0 1
1 3
2 5
3 7
4 9
5 32766
6 2091253915
value1 = 44, value2 = 88
address of arr[4]: 0x7ffeefaf3ae0
address of value1: 0x7ffeefaf3ac8
address of value2: 0x7ffeefaf3ac4
C信任程序员的原则,不检查边界,C程序可以运行更快。
10.1.5 指定数组的大小
10.2 多维数组
10.2.1 初始化二维数组
计算机内部,数组是按顺序存储的。
/* rain.c -- finds yearly totals, yearly average, and monthly
average for several years of rainfall data */
#include <stdio.h>
#define MONTHS 12 // number of months in a year
#define YEARS 5 // number of years of data
int main(void)
{
// initializing rainfall data for 2010 - 2014
const float rain[YEARS][MONTHS] =
{
{4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
{8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3},
{9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4},
{7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2},
{7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2}
};
int year, month;
float subtot, total;
printf(" YEAR RAINFALL (inches)\n");
for (year = 0, total = 0; year < YEARS; year++)
{ // for each year, sum rainfall for each month
for (month = 0, subtot = 0; month < MONTHS; month++)
subtot += rain[year][month];
printf("%5d %15.1f\n", 2010 + year, subtot);
total += subtot; // total for all years
}
printf("\nThe yearly average is %.1f inches.\n\n",
total/YEARS);
printf("MONTHLY AVERAGES:\n\n");
printf(" Jan Feb Mar Apr May Jun Jul Aug Sep Oct ");
printf(" Nov Dec\n");
for (month = 0; month < MONTHS; month++)
{ // for each month, sum rainfall over years
for (year = 0, subtot =0; year < YEARS; year++)
subtot += rain[year][month];
printf("%4.1f ", subtot/YEARS);
}
printf("\n");
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang rain.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
YEAR RAINFALL (inches)
2010 32.4
2011 37.9
2012 49.8
2013 44.0
2014 32.9
The yearly average is 39.4 inches.
MONTHLY AVERAGES:
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
7.3 7.3 4.9 3.0 2.3 0.6 1.2 0.3 0.5 1.7 3.6 6.7
10.2.2 其他多维数组
int box[10][20][30]
10.3 指针和数组
变相使用指针,数组名是数组首元素的地址
int flizny[10];
flizny == &flizny[0];//都表示数组首元素的内存地址,常量
// pnt_add.c -- pointer addition
#include <stdio.h>
#define SIZE 4
int main(void)
{
short dates [SIZE];
short * pti;
short index;
double bills[SIZE];
double * ptf;
pti = dates; // assign address of array to pointer
ptf = bills;
printf("%23s %15s\n", "short", "double");
for (index = 0; index < SIZE; index ++)
printf("pointers + %d: %10p %10p\n",
index, pti + index, ptf + index);
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang pnt_add.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
short double
pointers + 0: 0x7ffee6ec3ae0 0x7ffee6ec3ac0
pointers + 1: 0x7ffee6ec3ae2 0x7ffee6ec3ac8
pointers + 2: 0x7ffee6ec3ae4 0x7ffee6ec3ad0
pointers + 3: 0x7ffee6ec3ae6 0x7ffee6ec3ad8
//short类型占用2字节,double类型占用8字节
dates + 2 == &dates[2];
*(dates + 2) == dates[2];
/* day_mon3.c -- uses pointer notation */
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
int index;
for (index = 0; index < MONTHS; index++)
printf("Month %2d has %d days.\n", index +1,
*(days + index)); // same as days[index]
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang day_mon3.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
Month 1 has 31 days.
Month 2 has 28 days.
Month 3 has 31 days.
Month 4 has 30 days.
Month 5 has 31 days.
Month 6 has 30 days.
Month 7 has 31 days.
Month 8 has 31 days.
Month 9 has 30 days.
Month 10 has 31 days.
Month 11 has 30 days.
Month 12 has 31 days.
10.4 函数、数组和指针
// sum_arr1.c -- sums the elements of an array
// use %u or %lu if %zd doesn't work
#include <stdio.h>
#define SIZE 10
int sum(int ar[], int n);
int main(void)
{
int marbles[SIZE] = {20,10,5,39,4,16,19,26,31,20};
long answer;
answer = sum(marbles, SIZE);
printf("The total number of marbles is %ld.\n", answer);
printf("The size of marbles is %zd bytes.\n",
sizeof marbles);
return 0;
}
int sum(int ar[], int n) // how big an array?
{
int i;
int total = 0;
for( i = 0; i < n; i++)
total += ar[i];
printf("The size of ar is %zd bytes.\n", sizeof ar);
return total;
}
[wlsh@wlsh-MacbookPro] ch10$ clang sum_arr1.c
sum_arr1.c:26:53: warning: sizeof on array function parameter will return size of 'int *' instead of 'int []' [-Wsizeof-array-argument]
printf("The size of ar is %zd bytes.\n", sizeof ar);
^
sum_arr1.c:19:13: note: declared here
int sum(int ar[], int n) // how big an array?
^
1 warning generated.
//clang确实比gcc强大
gcc执行结果:
The size of ar is 8 bytes.
The total number of marbles is 190.
The size of marbles is 40 bytes
//marble内含10个int类型的值,每个值占4个字节,所以整个marble的大小是40字节,但是ar才8个字节,因为ar不是数组本身,是一个指向marbles数组首元素的指针。系统用8字节存储地址,所以指针变量的大小是8字节
10.4.1 使用指针形参
/* sum_arr2.c -- sums the elements of an array */
#include <stdio.h>
#define SIZE 10
int sump(int * start, int * end);
int main(void)
{
int marbles[SIZE] = {20,10,5,39,4,16,19,26,31,20};
long answer;
answer = sump(marbles, marbles + SIZE);
//下标从0开始,所以marbles + size指向数组末尾的下一个位置,如果指向最后一个元素则是marbles + size -1
printf("The total number of marbles is %ld.\n", answer);
return 0;
}
/* use pointer arithmetic */
int sump(int * start, int * end)
{
int total = 0;
while (start < end)
{
total += *start; // add value to total
start++; // advance pointer to next element
//total += *start++;
//*和++的优先级相同,结合律从右往左,使用后缀形式意味着先把指针指向位置上的值加到total上,然后再递增指针,
//total += *(start++);
}
return total;
}
[wlsh@wlsh-MacbookPro] ch10$ clang sum_arr2.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
The total number of marbles is 190.
/* order.c -- precedence in pointer operations */
#include <stdio.h>
int data[2] = {100, 200};
int moredata[2] = {300, 400};
int main(void)
{
int * p1, * p2, * p3;
p1 = p2 = data;
p3 = moredata;
printf(" *p1 = %d, *p2 = %d, *p3 = %d\n",
*p1 , *p2 , *p3);
printf("*p1++ = %d, *++p2 = %d, (*p3)++ = %d\n",
*p1++ , *++p2 , (*p3)++);
printf(" *p1 = %d, *p2 = %d, *p3 = %d\n",
*p1 , *p2 , *p3);
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang order.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
*p1 = 100, *p2 = 100, *p3 = 300
*p1++ = 100, *++p2 = 200, (*p3)++ = 300
*p1 = 200, *p2 = 200, *p3 = 301
10.4.2 指针表示法和数组表示法
处理数组的函数实际上用指针作为参数,即可以选在数组表示法还是指针表示法。
指针表示法更接近机器语言,编译器在编译时能生成效率更高的代码。
//无论ar是数组名还是还是指针变量,表达式都没问题。
ar[i] == *(ar + i)
10.5 指针操作
// ptr_ops.c -- pointer operations
#include <stdio.h>
int main(void)
{
int urn[5] = {100,200,300,400,500};
int * ptr1, * ptr2, *ptr3;
ptr1 = urn; // assign an address to a pointer
ptr2 = &urn[2]; // ditto
// dereference a pointer and take
// the address of a pointer
printf("pointer value, dereferenced pointer, pointer address:\n");
printf("ptr1 = %p, *ptr1 =%d, &ptr1 = %p\n",
ptr1, *ptr1, &ptr1);
// pointer addition
ptr3 = ptr1 + 4;
printf("\nadding an int to a pointer:\n");
printf("ptr1 + 4 = %p, *(ptr4 + 3) = %d\n",
ptr1 + 4, *(ptr1 + 3));
ptr1++; // increment a pointer
printf("\nvalues after ptr1++:\n");
printf("ptr1 = %p, *ptr1 =%d, &ptr1 = %p\n",
ptr1, *ptr1, &ptr1);
ptr2--; // decrement a pointer
printf("\nvalues after --ptr2:\n");
printf("ptr2 = %p, *ptr2 = %d, &ptr2 = %p\n",
ptr2, *ptr2, &ptr2);
--ptr1; // restore to original value
++ptr2; // restore to original value
printf("\nPointers reset to original values:\n");
printf("ptr1 = %p, ptr2 = %p\n", ptr1, ptr2);
// subtract one pointer from another
printf("\nsubtracting one pointer from another:\n");
printf("ptr2 = %p, ptr1 = %p, ptr2 - ptr1 = %td\n",
ptr2, ptr1, ptr2 - ptr1);
// subtract an integer from a pointer
printf("\nsubtracting an int from a pointer:\n");
printf("ptr3 = %p, ptr3 - 2 = %p\n",
ptr3, ptr3 - 2);
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang ptr_ops.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
pointer value, dereferenced pointer, pointer address:
ptr1 = 0x7ffee66b6ad0, *ptr1 =100, &ptr1 = 0x7ffee66b6ac0
adding an int to a pointer:
ptr1 + 4 = 0x7ffee66b6ae0, *(ptr4 + 3) = 400
values after ptr1++:
ptr1 = 0x7ffee66b6ad4, *ptr1 =200, &ptr1 = 0x7ffee66b6ac0
values after --ptr2:
ptr2 = 0x7ffee66b6ad4, *ptr2 = 200, &ptr2 = 0x7ffee66b6ab8
Pointers reset to original values:
ptr1 = 0x7ffee66b6ad0, ptr2 = 0x7ffee66b6ad8
subtracting one pointer from another:
ptr2 = 0x7ffee66b6ad8, ptr1 = 0x7ffee66b6ad0, ptr2 - ptr1 = 2
subtracting an int from a pointer:
ptr3 = 0x7ffee66b6ae0, ptr3 - 2 = 0x7ffee66b6ad8
[wlsh@wlsh-MacbookPro] ch10$
10.6 保护数组中的数据
编写一个处理基本类型的函数时,要选择的是传递int类型的值还是传递指向int的指针,通常都是直接传递数值,只有程序需要在函数中改变数值时,才会传递指针。
对于数组别无选择,必须传递指针,因为这样效率高,如果一个函数按值传递数组,则必须分配足够的空间来存储原数组的副本,然后把原数组所有的数据拷贝至新的数组中,如果把数组的地址传递给函数,让函数直接处理原数组则效率更高。
传递地址会导致一些问题。C通常都按值传递数据,因为这样做可以保证数据的完整性。如果函数使用的是原始数据的副本,就不会意外修改原始数据。但是,处理数组的函数通常都需要使用原始数据,因此这样的函数可以修改原数据
10.6.1 对形式参数使用const
int sum(const int ar[],int n) //函数原型
int sum(const int ar[],int n) {
//函数定义
}
const告诉编译器,该函数不能修改ar指向的数组中的内容。如果在函数中不小心使用类似ar[i]++的表达式,编译器会捕获这个错误,并生成一条错误信息。
即该函数处理数组时将其视为常量。
/* arf.c -- array functions */
#include <stdio.h>
#define SIZE 5
void show_array(const double ar[], int n);
void mult_array(double ar[], int n, double mult);
int main(void)
{
double dip[SIZE] = {20.0, 17.66, 8.2, 15.3, 22.22};
printf("The original dip array:\n");
show_array(dip, SIZE);
mult_array(dip, SIZE, 2.5);
printf("The dip array after calling mult_array():\n");
show_array(dip, SIZE);
return 0;
}
/* displays array contents */
void show_array(const double ar[], int n)
{
int i;
for (i = 0; i < n; i++)
printf("%8.3f ", ar[i]);
putchar('\n');
}
/* multiplies each array member by the same multiplier */
void mult_array(double ar[], int n, double mult)
{
int i;
for (i = 0; i < n; i++)
ar[i] *= mult;
}
[wlsh@wlsh-MacbookPro] ch10$ clang arf.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
The original dip array:
20.000 17.660 8.200 15.300 22.220
The dip array after calling mult_array():
50.000 44.150 20.500 38.250 55.550
10.6.2 const的其他内容
const不允许使用pd修改它所指向数据的值。
把const数据或非const数据的地址初始化为指向const的指针或为其赋值是合法的。
double rates[5] = {1 , 2, 3, 4, 5}
const double locked[4] = {1, 2, 4, 5}
const double *pc = rates ; //const
pc = locked;
pc = &rates[3];
double* pnc = rates; //非const
pnc = locked; 无效 只能把非const数据的地址赋给普通指针
pnc = &rates[3];有效
10.7 指针和多维数组
/* zippo1.c -- zippo info */
#include <stdio.h>
int main(void)
{
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5, 7} };
printf(" zippo = %p, zippo + 1 = %p\n",
zippo, zippo + 1);
printf("zippo[0] = %p, zippo[0] + 1 = %p\n",
zippo[0], zippo[0] + 1);
printf(" *zippo = %p, *zippo + 1 = %p\n",
*zippo, *zippo + 1);
printf("zippo[0][0] = %d\n", zippo[0][0]);
printf(" *zippo[0] = %d\n", *zippo[0]);
printf(" **zippo = %d\n", **zippo);
printf(" zippo[2][1] = %d\n", zippo[2][1]);
printf("*(*(zippo+2) + 1) = %d\n", *(*(zippo+2) + 1));
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang zippo1.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
zippo = 0x7ffee04d3ac0, zippo + 1 = 0x7ffee04d3ac8
zippo[0] = 0x7ffee04d3ac0, zippo[0] + 1 = 0x7ffee04d3ac4
*zippo = 0x7ffee04d3ac0, *zippo + 1 = 0x7ffee04d3ac4
zippo[0][0] = 2
*zippo[0] = 2
**zippo = 2
zippo[2][1] = 3
*(*(zippo+2) + 1) = 3
zippo[m][n] == *(*(zippo + m) + n)
pz[m][n] == *(*(pz+m) +n)
10.7.1 指针多维数组的指针
/* zippo2.c -- zippo info via a pointer variable */
#include <stdio.h>
int main(void)
{
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5, 7} };
int (*pz)[2];
pz = zippo;
printf(" pz = %p, pz + 1 = %p\n",
pz, pz + 1);
printf("pz[0] = %p, pz[0] + 1 = %p\n",
pz[0], pz[0] + 1);
printf(" *pz = %p, *pz + 1 = %p\n",
*pz, *pz + 1);
printf("pz[0][0] = %d\n", pz[0][0]);
printf(" *pz[0] = %d\n", *pz[0]);
printf(" **pz = %d\n", **pz);
printf(" pz[2][1] = %d\n", pz[2][1]);
printf("*(*(pz+2) + 1) = %d\n", *(*(pz+2) + 1));
return 0;
}
[wlsh@wlsh-MacbookPro] ch10$ clang zippo2.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
pz = 0x7ffeed436ac0, pz + 1 = 0x7ffeed436ac8
pz[0] = 0x7ffeed436ac0, pz[0] + 1 = 0x7ffeed436ac4
*pz = 0x7ffeed436ac0, *pz + 1 = 0x7ffeed436ac4
pz[0][0] = 2
*pz[0] = 2
**pz = 2
pz[2][1] = 3
*(*(pz+2) + 1) = 3
10.7.2 指针的兼容性
int n = 5;
double x;
x = n; //类型转换
int* p1 = &n;
double* pd = &x;
pd = p1; //编译时错误
int* pt;
int (*pa)[3];
int ar1[2][3];
int ar2[3][2];
int **p2; //一个指向指针的指针
pt = &ar1[0][0];
pt = ar1[0];
pt = ar1; 错误
//pt指向一个int类型值,而ar1指向一个内含3个int类型元素的值
pa = ar1; //都是指向内含3个int类型元素数组的指针
pa = ar2; 错误
p2 = &pt; //both pointer-to-int *
*p2 = ar2[0]; //都是指向int的指针
p2 = ar2; //错误
//p2指向指针的指针,它指向的指针指向int,而ar2是指向数组的指针,该数组包含2个int类型的元素
10.7.3 函数和多维数组
// array2d.c -- functions for 2d arrays
#include <stdio.h>
#define ROWS 3
#define COLS 4
//ar指向一个内含4个int类型值的数组(ar 16字节)
void sum_rows(int ar[][COLS], int rows);
void sum_cols(int [][COLS], int ); // ok to omit names
int sum2d(int (*ar)[COLS], int rows); // another syntax
int main(void)
{
int junk[ROWS][COLS] = {
{2,4,6,8},
{3,5,7,9},
{12,10,8,6}
};
sum_rows(junk, ROWS); //数组名
sum_cols(junk, ROWS);
printf("Sum of all elements = %d\n", sum2d(junk, ROWS));
return 0;
}
void sum_rows(int ar[][COLS], int rows)
{
int r;
int c;
int tot;
for (r = 0; r < rows; r++)
{
tot = 0;
for (c = 0; c < COLS; c++)
tot += ar[r][c];
printf("row %d: sum = %d\n", r, tot);
}
}
void sum_cols(int ar[][COLS], int rows)
{
int r;
int c;
int tot;
for (c = 0; c < COLS; c++)
{
tot = 0;
for (r = 0; r < rows; r++)
tot += ar[r][c];
printf("col %d: sum = %d\n", c, tot);
}
}
int sum2d(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;
}
[wlsh@wlsh-MacbookPro] ch10$ clang array2d.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
row 0: sum = 20
row 1: sum = 24
row 2: sum = 36
col 0: sum = 17
col 1: sum = 19
col 2: sum = 21
col 3: sum = 23
Sum of all elements = 80
10.8 变长数组(VLA)
前面的学习,处理二维数组,只把数组的行数作为函数的行参,而列数却内置在函数体内。
要创建一个能处理任意大小二维数组的函数
C99新增变长数组(variable-length array.VLA),允许使用变量表示数组的维度。
//vararr2d.c -- functions using VLAs
#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("3x5 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;
}
// function with a VLA parameter
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;
}
[wlsh@wlsh-MacbookPro] ch10$ clang vararr2d.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
3x5 array
Sum of all elements = 80
2x6 array
Sum of all elements = 315
3x10 VLA
Sum of all elements = 270
10.9 复合字面量
C99新增复合字面量(compound literal),如果有代表数组和结构内容的复合字面量,在编程时会更方便。
int diva[2] = {10,20}
(int [2]){10,20}
复合字面量提供只临时需要的值的一种手段,复合字面量具有块作用域,这意味着一旦离开定义复合字面量的块,程序将无法保证字面量是否存在。即复合字面量的定义在最内存的花括号内
// flc.c -- funny-looking constants
#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;
}
[wlsh@wlsh-MacbookPro] ch10$ clang flc.c
[wlsh@wlsh-MacbookPro] ch10$ ./a.out
total1 = 30
total2 = 4
total3 = 27
10.10 关键概念
10.11 本章小结