第10章 数组和指针

15 篇文章 1 订阅
订阅专栏

关键字: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 本章小结

 

 

 

 

 

 

 

 

C++期末实践程序设计与数组作为参数的注意事项
主要记录一些问题处理记录,部分是作为知识库使用
12-29 5766
小表弟发来的求助信号 并补充说要5种写法才算过关。 要点 先不说要几种写法,来说说这个实践的目的,也就是我们常常说的需求。 从题目本身说明是 面向对象程序设计 的考察;源文件和头文件分开,进一步说明是C++ 面向对象程序设计,同时也是C++程序设计的标准工程管理方式(头文件、源文件各自在一个文件中),只是在学习的时候往往一个文件将所有的代码放一个文件中。 类定义,实际上已经指明了类的属性以及需要具备的函数: 成绩要求用数组,是对数组的考察: 数组的初始、赋值、传递,别小看,容易掉坑里。 用自己的真实学号,
C语言笔记
BlizCp的博客
12-17 1024
1、cypher1.c //更改输入空格不变 #include <stdio.h> #define SPACE ' '//SPACE表示单引号+空格+单引号 int main(void){ char ch; ch = getchar();//读取一个字符 while (ch != '\n'){//当一行未结束时 //将getchar()读取键盘输入的值赋给ch,然后再判断ch !='\n',不是换行符,则为真 if(ch == SPACE){/
C语言声明与定义
ccq1029的专栏
01-24 1139
很久没接触C语言了,今天遇到声明与定义的问题,于是找到下面的解释: 声明(declaration )指定了一个变量的标识符,用来描述变量的类型,是类型还是对象,或者函数等。声明,用于编译器(compiler)识别变量名所引用的实体。以下这些就是声明: extern int bar; extern int g(int, int); double f(int, double); // 对于函数
Android 回编译时候大量报错:declared here is not defined
你的外祖父的博客
07-15 2810
Android 游戏这块出包的时候避免少不了反编译回编译签名,今天在回编译的时候遇到报错,说是values文件下的string.xml、color.xml、style.xml等文件的部分资源declared here is not defined(这里就不贴图了哈),这是因为这几个文件被你覆盖掉了,原来有的资源那些系统找不到就会报错,布局文件如果有重复的可以覆盖掉整个文件,但是这里的资源文件就不行了,需要做的是合并在一起,就是把你现有的加进原有的里面,然后回编译,就不会出现这个问题啦… ...
Linux——错误报告合集(1)
qq_52479948的博客
11-01 3581
Linux报错合集
C语言程序设计第4数组指针
04-09
在第四数组指针”中,我们主要探讨了以下几个知识点: 1. **数组的概念**: 数组是一组相同类型的变量,它们按照下标顺序存储在连续的内存空间里。数组通过一个唯一的标识符(数组名)来表示,数组名加上...
第5 数组指针3.pdf
11-23
在本中,我们将深入探讨数组指针的相关知识点。 首先,数组的定义和初始化是学习的基础。一维数组可以看作是一条线性的元素序列,而二维数组则可以视为由多个一维数组组成的矩阵。例如,`int num[6]`定义了一个...
VC++-第4-数组指针ppt课件.ppt
11-17
"VC++数组指针ppt课件" 本资源是关于VC++数组指针的ppt课件,涵盖...本资源涵盖了数组指针的基本概念、定义、使用方法和实际应用,旨在帮助学习者快速掌握VC++数组指针的使用方法,并在实际应用中发挥其优势。
C++ 程序设计课件:第五 数组指针.ppt
09-21
在C++编程中,数组指针是两个非常重要的概念,尤其在第五"数组指针"中,我们将深入探讨这两个主题。数组是存储同类型数据的有序集合,而指针则是用来存储变量地址的数据类型,使得我们可以直接操作内存。 5.1...
C 程序设计课件:第五 数组指针.ppt
06-18
### C程序设计课件:第五 数组指针 #### 5.1 数组 - **5.1.1 数组数组元素及其存储方式** - **数组的定义**: - 数组是一种顺序容器,由单一类型元素组成的一个有序集合。 - 示例:`int fibon[10]={0,1,...
C和指针 第4 语句 4.13 问题
weixin_客子光阴的博客
06-12 373
C和指针 第4 语句 4.13 问题
C语言阴影参数是什么,c – g – 阴影模板参数的错误,而g -5不
weixin_42467374的博客
05-18 531
参见英文答案 >Can a parameter of a template template parameter cause shadowing?1个请看以下示例:#include template class Container>std::vector To_Vector(Container const&amp...
一个C++原子变量初始化编译报错问题
qq_34999565的博客
07-27 6305
代码如下: #include <atomic> std::atomic_int count = 0; int main() { // Do something } 这段代码编译之后会报如下错误: use of deleted function ‘std::__atomic_base<_IntTp>::__atomic_base(const std::__atomic_base<_IntTp>&) [with _ITp = int]’ std::at
前端学习C语言 - 函数和关键字
最新发布
m0_62396648的博客
06-20 529
基本用法实现一个 add() 函数。// 自定义函数,用于计算两个整数的和int add(int a, int b) { // a, b 叫形参return sum;// 调用自定义函数计算两个整数的和// num1, num2 叫实参printf("两个整数的和为:%d\n", result);return 0;其中a, b 叫形参,num1, num2 叫实参。Tip// 3个形参,2个实参// 2个形参,3个实参函数调用过程通过函数名找到函数的入口地址。
ts-react——“xx“ was also declared here.【声明错误】
bidang3275的博客
12-06 2057
问题描述 解决方法 沿着目录网上找 node_modules 目录,删除掉该目录即可
二维数组越界和初始化问题
haoyun的博客
01-25 2492
二维数组越界问题 #include <stdio.h> int main(int argc, char *argv[]) { int a[][2]={1,2,3,5,6}; for (int i=0;i<3;i++) { for (int j=0;j<2;j++) { if (a[i][j]=='\0') { continue; } printf("%d ",a[i][j]); } } printf("\n %d ",
换个角度掌握C语言一维数组指针
strongerHuang
08-01 352
关注、星标公众号,不错过精彩内容转自:嵌入式Hacker正文目录:1.数组名是该数组首元素的地址 2.用指针操作数组 3.数组指针的关系密切 4. 编写处理一维数组的函数:传递数...
c语言declare.h的作用,关于C语言预处理面试题有哪些?
weixin_42117082的博客
05-16 347
本文是作者收集了一些关于C语言预处理面试题,此题可以为正在找工作的同事们提供很好的帮助。所以今天就写篇推送给大伙好好讲讲这写关于预处理的面试题,也让我们的学习尽可能和实际岗位需求接轨,话不多说了,请看题:问题1:什么是预编译?何时需要预编译?答:预编译又称预处理,是整个编译过程最先做的工作,即程序执行前的一些预处理工作。主要处理#开头的指令。如拷贝#include包含的文件代码、替换#define...
【c编译问题】multiple definition of "' first defined here 错误
热门推荐
n1wer的专栏
06-13 2万+
最近在移植代码的时候,编译出现的问题:“multiple definition of  ‘g_dl_stcuct’ first defined here”的错误。在网上找来半天都是说没有加头文件编译宏导致重复引用的问题:#ifndef _TEST_H_#define _TEST_H_。。。#endif但是我检查了都文件发现相关头文件都有相关保护的。后来仔细研究这段话“multiple defini...
写文章

热门文章

  • Scipy.Optimize 16201
  • CUDA(Ⅶ):使用事件(event)来测量性能 10461
  • CUDA(Ⅵ):常量内存(Constant Memory) 7242
  • CUDA(Ⅷ):纹理内存(Texture Memory) 6734
  • CUDA(Ⅱ):CUDA C入门 6593

分类专栏

  • C Primer Plus 15篇
  • C++ Primer Plus 6篇
  • LeetCode 1篇
  • Python 4篇
  • CMU 15-213 ICS 3篇
  • Udacity CS-334 IPP 5篇
  • Machine Learning in Action 1篇
  • CUDA By Example 11篇
  • 软件安装 6篇
  • Linux高级程序设计
  • Udacity Python
  • Pytorch 4篇

最新评论

  • CUDA(Ⅷ):纹理内存(Texture Memory)

    m0_68835353: 我的更慢,都到4000多了,请问你解决了吗

  • CUDA(Ⅵ):常量内存(Constant Memory)

    Arsmart: 感谢!这篇帖子很有用!!!!

  • 第4章 复合类型

    时是石头: 博主代码风格设置方便分享一下么,感觉好喜欢

  • 第12章 存储类别、链接和内存管理(未完结)

    edaplayer: 直接打个书名《c primer plus第6版》就好了

  • Scipy.Optimize

    Annie003: 我这么写会报错: TypeError: unsupported operand type(s) for -: 'tuple' and 'tuple' 请问您是用这个代码运行过是么

最新文章

  • Task5(2天)】PyTorch实现L1,L2正则化以及Dropout 1.了解知道Dropout原理 2.用代码实现正则化(L1、L2、Dropout) 3.Dropout的numpy实现 4.P
  • Pytorch打卡任务(四)
  • Pytorch打卡任务(三)
2019年58篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

玻璃钢生产厂家河北超市商场美陈销售园林玻璃钢动物雕塑销售厂家四川玻璃钢雕塑成都激光切割机滨州小品系列玻璃钢雕塑厂家义马商场美陈绿植墙公园景观玻璃钢雕塑制作湖南玻璃钢雕塑加工山西玻璃钢青椒雕塑湖北玻璃钢卡通雕塑阿狸价格商场美陈床哪有玻璃钢雕塑加工玻璃钢雕塑修补打磨商场美陈仿真树兰州人物玻璃钢雕塑安装德阳玻璃钢雕塑摆件施工价格邢台节日商场美陈定南玻璃钢雕塑厂家玻璃钢雕塑订制西安弘昌弘陕西玻璃钢雕塑厂家广东商场美陈公司徐州玻璃钢广场雕塑厂家双十一商场美陈效果图河北玻璃钢艺术雕塑甘肃玻璃钢商场美陈雕塑许昌玻璃钢雕塑厂在四川室内商场美陈供货商衢州百货商场美陈商场美陈专员工作问题户内玻璃钢雕塑方法山西卡通玻璃钢雕塑香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化