【C语言】数组和指针

无论是预习还是复习,看后你定会学有所获。

数组

数组(array)是按顺序存储的一系列类型相同的值。

初始化数组

使用数组前必须先初始化它。
    int num[5] = { 31, 28, 31, 30, 31};

    const int days[] = { 31, 28, 31, 30, 31};
    for( int i = 0; index <sizeof days/sizeof days[0]; index++)
代码分析总结:
初始化方式:
法一:在方括号里定义好有几个元素,并用花括号进行初始化。
法二:在方括号内不进行定义,花括号中有初始化几个元素就有几个。
2. 使用const声明数组,程序只能从数组中检索值,并不能修改值。
3.有的只部分初始化数组,剩余的元素就会被初始化为0(取决于编译器)。
4.若初始化为int days[] = { 31, 28, 31, 30, 31};这种格式,则可以通过 sizeof days/sizeof days[0] 计算数组长度。

指定初始化器

    int days[6] = {31, [5] = 31};      //例1
    int stuff[] = {1, [6] = 23};       //例2
    int stuff[] = {1, [5] = 4, 2, 6};  //例3
代码分析总结:
1.可以在{ } 指定初始化 ,如例1中指定初始化元素 [5] = 31, 则数组将初始化为 31 0 0 0 31。
2. 假设方括号里没有定义个数,看{ }最后初始化到哪里,那就是元素的个数。
例2中有7个元素,例3中有8个元素.

给数组元素赋值

    int oxen[SIZE] = {5,3,2,8};    //只能在此处使用花括号进行初始化赋值
    int yaks[SIZE];
    
    yaks = oxen;                    //错误赋值
    yaks[SIZE] = oxen[SIZE];        //数组下标越界
    yaks[SIZE] = {5,3,2,8};
代码分析总结:
1.C不允许把数组作为一个单元赋给另一个数组 ,例如第4行。
2. 注意数组边界 :数组的最后一个元素是oxen[SIZE - 1],即第5行两个数组都超过了数组末尾。
3.除了初始化以外也不允许使用花括号列表的形式赋值

指定数组的大小

    int n = 8;
    int a1[6];                  //可以 整型常量表达式
    int a2[2*5+1];              //可以 整型常量表达式
    int a3[sizeof(int) + 1];    //可以 sizeof的值被视为整形常量
    int a4[-4];                 //不可以   数组大小必须大于0
    int a5[0];                  //不可以   数组大小必须大于0
    int a6[2.5];                //不可以   不是整型常量表达式
    int a7[(int)2.5];           //可以  已强制转换成int
    int a8[n];                   //可以  在上面已经对变量n进行赋值
代码分析总结:
1.声明数组时只能在方括号内使用 整型常量表达式
2. sizeof的值被视为整形常量。
3. 数组大小必须大于0.
4.方括号中 可以是字母,但字母在之前必须已赋值。

在for循环中使用数组

/*输入十个数并计算差值*/
#include <stdio.h>
#define SIZE 10    
#define PAR 72

int main()
{
    int index, score[SIZE];
    int sum = 0;
    float average;
    
    for( index = 0; index < SIZE; index++)
        scanf("%d", &score[index]);
        
    for( index = 0; index < SIZE; index++)
        printf("%5d", score[index]);
    printf("\n"); 
    for( index = 0; index < SIZE; index++)
        sum += score[index];
    average = (float)sum/SIZE;         //强制类型转换(float)
    printf("The handicap is %.1f.\n", average - PAR);
     
    return 0;
} 

代码分析总结:
1.使用#define明示常量定义数组长度,在以后修改程序中不用逐一修改了。
2. 无论输入多少值,在此程序中scanf()仅读取10个值,scanf()会跳过空白格(空格|换行符)。
3.在算平均数时因为可能得出来的不是整数,使用了强制类型转换(float)。

这里只能存储字符,并不是字符串。存储字符串可以将其存储在char数组中,但末尾一定要加‘\0'.(C语言字符串中细讲)

多维数组

float rain[5][12];
我们理解明白这个代码,多维数组就学会一半了。
数组rain有5个元素,每个元素都是内含12个float类型元素的数组。

假设要统计五年年总降水量和5年中每月的平均降水量,那么就需要双重for循环。

通过改变 for循环的条件 实现对二维数组的横向和竖向调用。(当然还能实现其他调用)
    for( year = 0, total = 0; year < YEARS; year++)
    {   //处理每一年的数据 
        for( month = 0, subtotal = 0; month < MONTHS; month++)
        ...   //处理每月的数据 
        ...   //处理每年的数据 
    }
    
    for( month = 0; month < MOINTHS; month++)
    {
        for( year = 0,subtotal = 0; year < YEARS; year++)
        ...   //处理每年的数据
        ...   //处理每月的数据 
    }

初始化二维数组

const float rain[2][3] = {{23,34}, {43,21}};
同一维数组,未被初始化的元素被统一初始化为零。

其他多维数组

int box[2][3][4];
处理三维数组要使用三重for循环,依此类推。
  • 这里只简单的认识二维数组,详细讲解在下文和指针交叉的模块。

指针

指针是一个值为内存地址的变量(或数据对象)。

ptr = &pooh;     //将pooh的地址赋给ptr.
对于这条语句,我们说ptr指向了pooh. ptr和&pooh的区别是ptr是变量,&pooh是常量。
或者说, ptr是可修改的左值,还可以指向别处,而&pooh是右值。
  • 下面是一个错误实例:

#include <stdio.h>
int main()
{
    int a = 20,b = 30;
    printf("%p %p\n", &a, &b);
    
    int *t = &a;
    &a = &b;   //编译错误    
   //&a是一个右值,是一个常量,不能将其修改,即变量的地址不可以修改 
    &b = t;
    
    printf("%p %p\n", &a, &b);
    return 0;
}

声明指针

    printer ptr;
上面要创建指针变量正确吗?
答:错误。 创建指针变量必须声明指针变量所指向的变量的类型。
原因有二:其一,不同的变量类型占用不同的储存空间,一些指针操作要求知道操作对象的大小。(在下文“指针和数组”中会讲到)
其二,程序必须知道存储在指定地址上的数据类型。

那么如何创建呢?

假设想把ptr声明为储存int类型变量地址的指针,就要使用*运算符,即间接运算符,或解引用运算符。

int *ptr;
long *pi;
float *pf;

long和float可能占用相同的存储空间,但是他们储存数字却大相径庭。

类型说明符表明了指针所指向对象的类型,*表明声明的变量是个指针。
例如int *ptr声明的是:ptr是个指针,*ptr是int类型。
ptr的值是个地址,在大多数系统内部,该地址由一个无符号整数表示。 但一些处理整数的操作不能用来处理指针。例如可以把两个整数相加,但是不能把两个指针相加。所以, 指针实际上是一个新类型,不是整数类型。因此,ANSI C专门为指针提供了 %p 格式的转换说明。

使用指针在函数中通信

如果要在被调函数中改变主调函数的变量,应使用指针作为函数的参数。
  • 类比我们之前使用的scanf( )函数就是这样。当程序把一个值读入变量时,调用的是scanf("%d", &x);scanf读取一个值,然后把该值存储到指定的地址上。

/*调换两个变量的值*/
#include <stdio.h>
void interchange(int *u,int *v);
int main()
{
    int x = 5, y = 10;
    printf("x = %d, y = %d\n", x, y);
    interchange(&x, &y);
    printf("x = %d, y = %d\n",x, y);
    
    return 0;
} 
void interchange( int *u, int *v)
{
    int temp = *u;
    *u = *v;
    *v = temp;
}
代码分析总结:
1.该函数传递的不是x和y的值,而是它们的地址,故而在函数声明中将声明为指针。
2. 第15行的int temp;定义了一个变量交换的中间变量,注意类型要和指针变量u所指的类型相同。
3.第16行的 *u = *v相当于语句 x = y. 如果不好理解的话我们再捋一遍, *u指的是变量y里的值,不是简单的一个数值10。当y的值改变成5,*u的值也改变了,是5。因为*u指的是变量y里的值。

指针和数组

这里,我要说 数组表示法就是在变相的使用指针。数组名是数组首元素的地址。

如果flizny是一个数组,下面的语句成立:

flizny == &flizny[0];
flizny和&flizny[0]二者等价,都表示数组首元素的内存地址。

两者都是常量,在程序运行过程中不会改变。但我们可以把它们赋值给指针变量,然后可以修改指针变量的值。

#include <stdio.h>
#define SIZE 5
int main()
{
    short dates[SIZE];
    short *ptr;
    double bills[SIZE];
    double *pti;
    int index;
    
    ptr = dates;               //利用数组名赋值
    pti = &bills[0];           //利用数组下标赋值
    for(index = 0; index < SIZE; index++)
        printf("pointer + %d:short %10p  double %10p\n",
        index, ptr + index, pti + index);

    return 0;
}
代码分析总结:
运行程序可知ptr + 1加的不是一个字节, 指针加1加的是增加一个储存单元 ,即它所指向类型的大小。对数组而言,这意味着加1后的地址是下一个元素的地址,而不是下一个字节的地址。这是为什么必须声明指针所指向对象类型的原因之一。

刚才我说数组名是数组首元素的地址。上面是将数组名赋给指针,那可不可以将数组名直接当指针用。

答案是可以的。

    dates + 2 == &dates[2];     //相同的地址
    *(dates + 2) == dates[2];    //相同的值
从这里我们发现,C语言标准在描述数组表示法时确实借助了指针。也就是说定义ar[n]的意思是*(ar + n)。可以认为 *(ar + n)的意思是”到内存的ar位置,然后移动n个单元,检索储存在那里的值”
不要混淆 *date + 2和 *(dates + 2)。 间接运算符*的优先级高于+,所以*dates+2相当于*(dates)+ 2,即dates第一个元素的值加2.

代码演示:

#include <stdio.h>
#define SIZE 5
int main()
{
    int days[SIZE] = {31,28,31,30,31};
    int index;
    
    for(index = 0; index < SIZE; index++)
        printf("%d\n",*(days + index));

    return 0;
}

该例演示了可以用指针表示数组。反过来,也可以用数组表示指针。在使用以数组为参数的函数时要注意这点。

函数、数组和指针

假设现在我们要编写一个处理数组的函数,该函数返回数组中所有元素之和,待处理的是名为marbles的int类型的数组。应该如何调用该函数呢?

total = sum(marables);
那么函数原型是什么呢?记住,数组名是该函数首元素的地址,所以 实际参数marables是一个存储int类型值的地址,应把它赋给一个指针形式参数,即该参数是一个指向int的指针。
int sum(int *ar);
但我们发现一个问题,就是求和时遍历数组不知道数组的大小啊,所以函数定义应这样改进。
int sum(int *ar, int n);
int sum(int ar[],int n);
int *ar和int ar[ ]形式都表示ar是一个指向int类型的指针。 但是int ar[ ]告诉我们ar指向的不仅仅是一个int类型值,还是一个int类型数组的元素。

下面的程序计算数组元素之和,综合运用函数、数组和指针

#include <stdio.h>
#define SIZE 5
int sum(int *ar,int n);     
int main()
{
    int days[SIZE] = {31,28,31,30,31};
    long answer;           //防止int类型表示不下,使用long. 
    
    answer = sum(days, SIZE);
    printf("Total:%4ld  SIZE days:%4zd\n",answer, sizeof days);
    //长整型使用%ld  sizeof类型使用%zd 或者%u / %lu

    return 0;
}
int sum(int *ar,int n)
{
    int index;
    int total = 0;
    
    for( index = 0; index < n; index++)
        total += *(ar + index);
    printf("printer is %zd bytes.\n",sizeof ar);
    
    return total;
}
第三行函数原型那需要自行起一个变量n表示数组的大小。不能使用SIZE,因为这里SIZE是常量5。

使用指针形参

利用函数处理数组必须知道何时开始,何时结束。 上面的sum( )函数使用指针形参标识数组开始,用一个整数形参表明待处理数组元素的个数(指针形参也表明了数组中元素的个数)但是这并不是处理数组的唯一方法。
还有一种方法是 传递两个指针,第一个指针指明数组的开始处(与第一种方法相同),第二个指针指明数组的结束处。
  • 下面程序演示了传递两个指针处理数组的方法:

#include <stdio.h>
#define SIZE 5
int sump( int *start, int *end);

int main()
{
    int marbles[SIZE] = {10,20,30,40,50};
    long answer;
    
    answer = sump( marbles, marbles + SIZE);
    printf("%The total is %ld", answer); 
    
    return 0; 
}
int sump( int *start, int *end)
{
    int total = 0;
    
    while( start < end)
    {
        total += *start;
        start++;
    }
    
    return total;
}
代码分析与总结:
1.该程序表明指针形参是个变量,这意味着可以用索引表明访问数组的哪个元素。
2.注意sump( )和sum( )循环结束条件的不同。
sum( )函数把元素的个数作为第二个参数,并把该参数作为循环测试的一部分。
sump( )函数则使用第二个指针来结束循环。下面详细分析
  • 这里,我再次说明下,sump()中的start是指针,可以进行start++的操作。但是如果在主函数中不可以使用数组名marbles++,因为数组名是一个地址常量,不是指针,不是变量。不能通过marblse++去修改marbles数组地址。代码如下:

#include <stdio.h>
#define SIZE 5

int main()
{
    int malb[SIZE] = {1, 2, 3, 4, 5};
    int index;
    int total = 0;
    
    for( index = 0; index < SIZE; index++){
        total += *(malb + index);     //正确 
//        total += *malb++;         错误写法 
    }
    
    printf("%d \n",total);
    
    return 0;
} 
“越界”指针
因为while循环的测试条件是一个不相等的关系,所以循环最后处理的元素是end所指向位置的前一个元素。这意味着end指向的位置实际上是在数组最后一个元素的后面。 C保证在给数组分配空间时,指向数组后面第一个位置的指针仍是有效的指针。 这使得while循环测试条件是有效的,因为start在循环中的最后的值是end。(在最后一次while循环中执行完start++后,start的值就是end的值。)
  • 越界指针的调用

answer = sump( marbles, marbles + SIZE);
*运算符和++运算符
  • 上面循环的代码优化

total += *start++;
  • 对比下这几种表示方法

*运算符和++运算符的优先级相同,但结合律是从右向左.
total += *start++;      //++放后面意味着先将start的值赋给total,再递增指针。
total += *++start;      //++放前面意味着先递增指针,再将start的值赋给total。
total += *(start)++;    //先解引用,再将值加1
total += *(start++);    //同第一行代码解释

指针操作

  1. 赋值:可以把地址赋给指针。例如将数组名、带地址运算符&的变量名、另一个指针进行赋值。但注意,地址应该是和指针类型兼容,例如不能把double类型的地址赋给int类型的地址。

  1. 解引用:*运算符给出指针指向地址上储存的值。再解释*p:*p表示说这个指针它所代表所指向的地址上的变量,那个值是表达式运算的结果,故而说指向地址上存储的值。

  1. 取址:和所有变量一样,指针变量也有自己的地址和值。对指针而言,&运算符给出指针本身的地址。

  1. 指针与整数相加减。这里的“整数”是和指针所指向类型的大小(以字节相乘)相乘,然后指针指向的地址再和这个“整数”相加减。如果相加的结果超出了初始化指针指向的数组范围,计算结果是未定义的。除非刚好超过数组末尾的第一个位置,C保证该指针有效。

  1. 递增递减指针。以递增指针为例,这步操作可以让该指针移动至数组的下一个元素。但指针本身的地址仍不变,毕竟,变量不会因为值发生变化就移动位置。

  1. 指针求差。可以计算两个指针的差值。通常是对一个数组而言,求差的单位与数组类型的单位相同。

  1. 较。使用关系运算符可以比较两个指针的值,前提是两个指针都指向相同类型的对象。

注意:
不能解引用未初始化的指针。指针未被初始化,其值是一个随机数,所以不知道5将存储在何处,存储可能导致程序出错。 创建一个指针时,系统只分配了存储本身的内存,并未分配存储数据的内存。因此,在使用指针之前,必须先用已分配的地址初始化它。
  • 下面就是一个初始化的实例:

    int malb = 7;
    int *ptr = &malb;
    *ptr = 5;

保护数组中的数据

当我们编写一个函数传递数组时,我们会想是否是要修改函数的值呢?如果是修改值,那么我们要传递指针。

/* 对数组中的每个元素都加val  */
void add_to( double a[], int n, double val)
{
    int i;
    
    for( i = 0; i < n i++)
       a[i] += val;
} 
/* 计算数组中所有元素之和  */
int sum( double a[], int n)     //错误代码编写
{
    int i;
    int total = 0;
    
    for( i = 0; i < n i++)
       total += a[i]++;       //错误的递增了每个元素的值
    
    return total;
} 
代码分析总结:
很明显我们看到,第一个函数add_to( )函数的功能是对数组中的每个元素都加val,就是说需要修改函数的值,且代码是正确的。但第二个代码是计算数组中所有元素之和,也就是说不需要修改代码的值,但第十六行对每个a[i]都递增了每一个元素的值,导致代码出错。虽说计算结果不会错,但是你却对每个元素都做了加一操作。

那有什么方法可以更好的避免呢?且向下看

对形式参数使用const

  • 如果函数的意图不是修改数组中的数据内容,那么在函数原型和函数定义中声明形式参数时应使用关键字const。

代码如下:

#include <stdio.h>
#define SIZE 6

void sum(const int *a, int n);
int main()
{
    int malb[SIZE] = { 3, 5, 6, 7, 2, 9};
    int answer = 0;
    
    answer = sum( malb, SIZE);
    printf("The total is %d. \n", answer);
    
    return 0; 
}
//int sum(const int a[], int n)
int sum(const int *a, int n)
{
    int i;
    int total = 0;
    
    for( i = 0; i < n; i++){
       total += a[i];
       printf("a[%d] = %d\n", i, *(a + i));
   }
    
    return total;
} 

const的其他内容

在前面,我们使用#define指令可以创建类似功能的符号常量,但是const的用法更为灵活。可以创建const数组、const指针和指向const的指针。

什么是指向const的指针呢?

答:就是创建好后无论是使用数组表示法还是指针表示法,都不能使用pd来更改它所指向的值。但是可以让pd指向别处。

double rates[5] = {1.4, 2.6, 3.2, 4.9, 5.1};
const double *pd = rates;
*pd = 7.9;        //不允许,不能使用pd来更改它所指向的值
pd++;            //允许,可以让pd指向别处
pd[2] = 2.3;     //不允许,不能使用pd来更改它所指向的值
rates = 3.4;      //允许,数组并不是const,可以修改值

  • 该图表示将const数据和非const数据的地址赋给const的指针是合法的,并且将非const数据赋给普通指针也是合法的。但是不能将const赋给普通指针,否则,就可以通过这个普通指针修改const的数据。

const double rates[5];
double locked;
/*  const指针   */
const double *pc = rates;      //有效
pc = locked;         //有效
pc = &rates[2];      //有效
/*   普通指针    */
double *pin = rates;     //无效
pin = locked;         //有效
  • 小总结:也就是说const放在*前面是不能修改指向数据的值。

那是否可以声明并一个不能指向其他位置但能修改数据的指针呢?

答案是可以的。

double malb[4];
double num;
double *const ptc = malb;
*ptc = 78.3;    //合法
ptc = &num;     //不合法

总结:当const放在了*前面指针可以指向其他位置,但不能修改数据的值;当const放在了*后面,指针不可指向其他地方,但可以修改数据的值;如果*前后都有const,则指针既不能指向其他位置,也不能修改变量的值。

//例如:
double malb[4];
double num;
const double * const pte = malb;
*pte = 78.3;     //非法
pte = &num;      //非法

指针和多维数组

可以看明白这张图片的内容吗?

如果云里雾里的话那就看接下来的内容吧,学完再返回来看哈。

里面有一个错误,你发现了吗?

处理多维数组的函数要用到指针,所以在使用这种函数之前,要先更深入的学习指针。

int zippo[4][2];

我们知道,该二维数组的数组名zippo是该数组首元素的地址,zippo的首元素是一个内含两个int值的数组,所以zippo是这个内含两个int值的数组的地址。下面,我们从指针的角度进行分析。

zippo = &zippo[0];
zippo[0] = &zippo[0][0];
  • zippo和zippo[0]的异同:因为zippo是数组首元素的地址,所以zippo的值和&zippo[0]的值相同。而zippo[0]本身是一个内含两个整数的数组,所以zippo[0]的值和它首元素(一个int 类型的整数)的地址(即&aippo[0][0]的值)相同。简而言之,zippo[0]是占用一个int大小对象的地址,而zippo是占用两个int大小对象的地址。由于这个整数和内含两个整数的数组都开始于同一个地址,所以zippo和zippo[0]的值相同。

  • zippo + 1 不等于 zippo[0] + 1再次解明:给指针或地址加一,其值会增加对应类型大小的数值。在这方面,zippo和zippo[0]不同,因为zippo指向的对象占用了两个int类型的大小,zippo[0]指向的对象只占用了一个int类型的大小。

  • 解引用一个指针(在指针前使用*运算符)或在数组名后使用带下标的[ ]运算符,得到引用对象代表的值。因为zippo[0]是该数组首元素(zippo[0][0])的地址,所以*(zippo[0])表示存储在zippo[0][0]上的值(即一个int类型的值)。与此类似,*zippo代表该数组首元素(zippo[0])所储存的值,但是zippo[0]本身是一个int类型值的地址。该值的地址是&zippo[0][0],所以*zippo就是&zippo[0][0]。对两个表达式应用解引用运算符表明,**zippo与*&zipp[0][0]等价,这相当于zippo[0][0],即一个int类型的值。简而言之,zippo是地址的地址,必须解引用两次才能获得原始值。地址的地址或指针的指针就是双重间接的例子。

指向多维数组的指针

在编写处理像zippo这样的二维数组的时候会用到指针。把指针声明为指向int类型还不够。因为指向int只能与zippo[0]的类型匹配,但是该元素是一个内含两个int类型的一维数组。因此,指针pz必须指向一个内含两个int类型值的数组,而不是指向一个int类型值,其声明如下:

   int (* pz)[2];    //pz指向一个内含两个内含int类型值的数组

为什么要在声明中使用圆括号,因为[ ]的优先级高于*。

    int *pax[2];

由于[ ] 优先级高,先与pax结合,所以pax成为一个内含两个元素的数组。然后* 表示pax数组内含两个指针。最后,int表示pax数组中的指针都指向int类型的值。因此,这行代码声明了两个指向int 的指针。所以,*先与pz结合,表明是指向一个数组指针,且是指向一个内含两个元素的指针。

指针的兼容性

指针之间的赋值比数值之间的赋值更严格。例如,不用类型转换就可以将int类型赋给double类型,但指针不能这样做。

int *pt;
int (*pa)[3];
int ar1[2][3];
int ar2[3][2];
int **p2;

pt = &ar1[0][0];   //可以,都是指向int类型的指针
pt = ar1[0];      //可以,都是指向int类型的指针,联想一维数组
pt = ar1;          //无效,ar1指向的是一个内含3个int类型的一维数组
pa = ar1;          //可以,都是指向一个内含3个int类型的一维数组
pa = ar2;       //无效,pa指向的是一个内含3个int类型的一维数组,ar2指向的是一个内含2个int类型的一维数组
p2 = &pt;       //可以
*p2 = ar2[0];    //可以,都是指向int类型的指针
p2 = ar2;         //p2指向的是int类型指针的指针,ar2指向的是一个内含两个int类型数组的指针。     

注意最后两行代码的解释!!!

和const之间的联系
int x = 20;
const int y = 23;
int * p1 = &x;               //可以
const int *p2 = &y;          //可以
const int **pp2;            
p1 = p2;               //不安全,将const指针赋给非const类型指针 
p2 = p1;                //有效, 将非const赋给了const指针
pp2 = &p1;              //不安全,嵌套指针类型赋值
const int **pp2;
int *p1;
const int n = 13;
pp2 = &p1;               //允许,不能通过**pp2修改它所指的内容
*pp2 = &n;                //有效,两者都是const。但是这将导致p1指向n。(*pp2已被修改)
*p1 = 10;                 //有效,但是这将修改n的内容

还记得上面的那张图吗,快检测下自己是不是学的很清晰了。

函数和多维数组

在函数体中,通常使用数组表示法进行相关操作。

假设要给函数some( )传递一个junk[3][4]的数组,可以这样:

void some( int ( *pt)[4] );
void some( int  pt[ ][4] );
  • 一般而言,声明一个指向N维数组的指针时,只能省略最左边方括号中的值。因为第一对方括号只用于表明这是个指针,而其他的方括号则用于描述指针所指向数据对象的类型。

变长数组

int sum2d( int rows, int cols, int ar[rows][cols]);

因为ar的声明要使用rows和cols,所以在形参列表中必须在声明ar之前先声明这两个形参。

int junk[ROWS-1][COLS-2];

复合字面量

字面量是除符号常量(#define)外的常量。例如5是int类型字面量“elephant”是字符串字面量。但是之前没有等价的数组常量。现在,我们有复合字面量可以创建匿名数组。

int diva[2] = {10, 20};
(int []){ 50, 20, 90};
因为复合字面量是匿名的,所以不能先创建然后再使用它,必须在创建的同时使用它。使用指针记录地址就是一种用法。
int (* ptr)[3];
ptr = ( int [2][3]){ {1, 2, 3}, { 4, 5, 6}};

还有一种用法就是传递给函数是不必先创建数组。

sum( (int []){1,2,3,4,5}, int 5};
  • 记住,复合字面量是提供字临时需要的值的一种手段。复合字面量具有块作用域,这意味着一旦离开定义字面量的块,程序将无法保证字面量是否存在。也就是说,复合字面量的定义是在最内层的花括号里。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

扬子期

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值