第10章 数组和指针

关键字:static

运算符:&、*(一元)

如何创建并初始化数组

指针、指针和数组的关系

编写处理数组的函数

二维数组

 

目录

10.1 数组

10.1.1 初始化数组

10.1.2 指定初始化器(C99)

10.1.3 给数组元素赋值

10.1.4 数组边界

10.1.5 指定数组的大小

10.2 多维数组

10.2.1 初始化二维数组

10.2.2 其他多维数组

10.3 指针和数组

 

10.4 函数、数组和指针

10.4.1 使用指针形参

10.4.2 指针表示法和数组表示法

10.5 指针操作

10.6 保护数组中的数据

10.6.1 对形式参数使用const

10.6.2 const的其他内容

10.7 指针和多维数组

10.7.1 指针多维数组的指针

10.7.2 指针的兼容性

10.7.3 函数和多维数组

10.8 变长数组(VLA)

10.9 复合字面量

10.10 关键概念

10.11 本章小结


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 本章小结

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值