C语言数组概念及其应用

一、数组

1. 基本概念

  • 逻辑:一次性定义多个相同类型的变量,并存储到一片连续的内存中
  • 示例:

int a[5];

  • 语法释义:
    • a 是数组名,即这片连续内存的名称
    • [5] 代表这片连续内存总共分成5个相等的格子,每个格子称为数组的元素
    • int 代表每个元素的类型,可以是任意基本类型,也可以是组合类型,甚至可以是数组
  • 初始化:在定义的时候赋值,称为初始化

// 正常初始化 int a[5] = {100,200,300,400,500}; int a[5] = {100,200,300,400,500,600}; // 错误,越界了 int a[ ] = {100,200,300}; // OK,自动根据初始化列表分配数组元素个数 int a[5] = {100,200,300}; // OK,只初始化数组元素的一部分

数组的真实存储

注意
  • 定义数组时,a[5],这里的5指的是定义数组内存放的元素个数的最大值,从1开始数。
  • 在利用数组下标查找元素时,下标是从0开始的,所以下标的最大值是是定义时数组元素的数值减一。数组下标其实叫做偏移量。

2. 数组元素的引用/初始化

  • 存储模式:一片连续的内存,按数据类型分割成若干相同大小的格子
  • 元素下标:数组开头位置的偏移量,a[0]引用第1个格子,a[1]引用第2个格子,以此类推

元素下标偏移量

示例:
int a[5]; // 有效的下标范围是 0 ~ 4
a[0] = 1;
a[1] = 66;
a[2] = 21;
a[3] = 4;
a[4] = 934;

a[5] = 62; // 错误,越界了
a    = 10; // 错误,不可对数组名赋值 


int b[5]={0}//不完全初始化,则定义一个数组,并全初始化为0
//用户输入数组进行赋值
for(int i=0;i<Strlen(b);i++){
    int ret_val=scanf("%d",&b[i]);
    if (ret_val!=1){
        while(getchar()!='\n');
        printf("请重新输入…\n");
        i—;                         
    }
}
注意

       int a[5]; // 有效的下标范围是 0 ~ 4

        a = 10; // 错误,不可对数组名赋值

         1.不可对数组名赋值原因:

                在大多数编程语言中,数组名代表的是数组在内存中的地址,是一个常量指针,不能被赋值。这是因为数组名在编译时被解释为一个指向数组首元素的指针,而指针是一个固定的内存地址。因此,尝试对数组名赋值会导致编译器报错。

        2.数组在定义的时候必须确定大小,而确定大小的方式有两种:
        3.初始化:

        [完全初始化]:数组大小和赋值数据个数相同

        [越界初始化]:赋值数据个数大于给定数组大小。则越界数据不会被存入数组,并且编译时会报错。

        [不完全初始化]:在对数组进行不完全初始化的时候,未初始化部分默认0

3. 各种类型的数组

3.1 字符数组
  • 概念:
  • 专门存放字符的数组,称为字符数组
  • 初始化:

char s1[5] = {'a', 'b', 'c', 'd', 'e'}; // s1存放的是字符序列,非字符串(因为这样子定义没有以'\0'结尾) //以下三种写法相同,存的都是一个字符串 char s2[6] = {'a', 'b', 'c', 'd', 'e', '\0'}; // s2存放了一个字符串 char s[6] = {"abcde"}; // 使用字符串直接初始化字符数组 char s[6] = "abcde" ; // 大括号可以省略

  • 元素引用

s[0] = 'A'; // 索引第一个元素,赋值为 'A'

数组长度:

函数strlen(字符串数组):计算的是数组中字符串的长度,不包含结束符'\0'

关键字sizeof(数组名):计算的是数组的占用字节数。如果是字符数组的话,一个字符刚好是一个字节,所以等于定义时[]中的数组大小。

注意点:

a. char s1[5] = {'a', 'b', 'c', 'd', 'e’};
        // s1存放的是字符序列,非字符串(因为这样子定义没有以"0'结尾)。只能说是字符数组。
b.字符数组和普通数组不一样的是,字符数组通常用于存储字符串,即以"0'(空字符)结尾的字符序 列->字符串数组
c.在打印字符串的时候,printf函数会一直打印字符串,除非遇到'\0'。

3.2 多维数组
  1. 概念:

                若数组元素类型也是数组,则该数组称为多维数组

  1. 声明多维数组:

        声明为多维数组必须具有除第一个维度以外的所有维度的边界,所以

int a[][]={{1,2,3},{4,5,6}};是错误的多维数组声明。

int a[][3]={{1,2,3},{4,5,6}};是正确的多维数组声明。

int a[5]={1,2,3,4,5}; 
int b[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 
printf("*b=%p\n",*b);

        此时打印出来的是一个地址,该地址为数组{1,2,3,4}的首元素的地址。因为二维数组中,母数组的子元素都是地址(子数组的首元素的地址),而在以上示例中,b代表母数组的第一个元素的地址,即子数组首元素的地址的地址,二级指针。所以*b(解引用b)得到的是子数组的首元素的地址。

        在C语言中,当你声明一个二维数组时,母数组的元素的地址已经分配完成,被确定为一个常量指针,可以被用于指向一个一维数组的首地址,但是指针本身不可修改,所以数组名是不能被赋值的,而母数组的元素就是一个数组名。c语言中,数组名被解释为指向数组第一个元素的指针,且这个指针是常量,不允许修改。

        数组类型 数组名 [ 数组元素的数量 ] [ 数组类型的大小 ]

    int* ptrArrArr[3][2];

    int a = 1, b = 2, c = 3, d = 4, e = 5, f = 6;

    int* ptr1[2] = {&a, &b};
    int* ptr2[2] = {&c, &d};
    int* ptr3[2] = {&e, &f};

    ptrArrArr[0] = ptr1;
    ptrArrArr[1] = ptr2;
    ptrArrArr[2] = ptr3;

此时报错为:赋值给数组类型的表达式

error: assignment to expression with array type

160 | ptrArrArr[0] = &ptr1;

在C语言中,数组名是不能被赋值的,因为数组名本身就是数组首元素的地址,是一个常量指针,无法修改。因此,你无法直接给

ptrArrArr[0]、

ptrArrArr[1]和

ptrArrArr[2]赋值。

示例:

int a[2][3]; 

// 代码释义:
// 1, a[2]   是数组的定义,表示该数组拥有两个元素
// 2, int [3]是元素的类型,表示该数组元素是一个具有三个元素的整型数组,
//数组(元素)类型的元素个数是不能省略的
内存映像:

语法
  • 多维数组的语法跟普通的一维数组语法完全一致
  • 初始化:
int a[2][3] = {{1,2,3}, {4,5,6}}; // 数组的元素是另一个数组

int a[2][3] = {{1,2,3}, {4,5,6}, {7,8,9}}; // 错误,数组元素个数越界了
int a[2][3] = {{1,2,3}, {4,5,6,7}};        // 错误,越界了

int a[ ][3] = {{1,2,3}, {4,5,6}}; // OK,自动根据初始化列表分配数组元素个数
int a[2][3] = {{1,2,3}};          // OK,只初始化数组元素的一部分
int a[2][ ] = {{1,2,3}, {4,5,6}}; // 编译失败,C语言只会自动计算数组的声明中元素个数,即数组声明可以自动补齐。但是元素声明无法自动补齐

int a[2][ ] = {{1,2,3}, {4,5,6}};编译失败,

C语言只会自动计算数组的声明中元素个数,即数组声明可以自动补齐。但是元素声明无法自动补齐

元素引用:
// a[0] 代表第一个元素,这个元素是一个具有 3 个元素的数组:{1,2,3}
// a[1] 代表第二个元素,这个元素也是一个具有 3 个元素的数组:{4,5,6}

printf("%d", a[0][0]); // 输出第一个数组的第一个元素,即1
printf("%d", a[1][2]); // 输出第二个数组的第三个元素,即6

注意点

  • int a[2][ ] = {{1,2,3}, {4,5,6}}; // 编译失败,C语言只会自动计算数组的声明中元素个数,即数组声明可以自动补齐。但是元素声明无法自动补齐
  • 对于1中的a数组,不能通过a[0]={10,20,30}的方式进行重新赋值,因为不能直接对数组名进行赋值,而a[0]是数组{1,2,3}的数组名。(赋值符号的左右两边应该是相同类型的,而在C语言中,数组名代表的是数组的首地址,是一个常量指针,因此不能直接对数组名进行赋值。当我们声明一个数组时,数组名就代表了该数组在内存中的起始地址,这个地址是固定的,无法改变。)
  • 要重新赋值可以用a[0][0]=10,a[0][1]=20,a[0][2]=30,的方式进行赋值。

4. 数组语法解剖

  • 任意的数组,不管有多复杂,其定义都由两部分组成。
    • 第1部分:说明元素的类型,可以是任意的类型(除了函数)
    • 第1部分:说明数组名和元素个数

  • 示例:
int   a[4];             // 第2部分:a[4]; 第1部分:int
int   b[3][4];          // 第2部分:b[3]; 第1部分:int [4]
int   c[2][3][4];       // 第2部分:c[2]; 第1部分:int [3][4]
int  *d[6];             // 第2部分:d[6]; 第1部分:int *
int (*e[7])(int, char); // 第2部分:e[7]; 第1部分:int (*)(int, float)
  • 注解:
    • 上述示例中,a[4]、b[3]、c[2]、d[6]、e[7]本质上并无区别,它们均是数组
    • 上述示例中,a[4]、b[3]、c[2]、d[6]、e[7]唯一的不同,是它们所存放的元素的不同
    • 第1部分的声明语句,如果由多个单词组成,C语言规定需要将其拆散写到第2部分的两边

练习:

1、判断声明是否正确

假设有如下声明:

float a[3];

float b[2][3];

float c = 2.2, *p;

则下列语句中那些是正确的,哪些是错误的?原因是什么?

a[2] = c;
a = c;
scanf("%f", &a);
printf("%f", a[3]);
b[1][2] = a[2];
b[1] = a; 
p = c;
p = a; 
  • 解析
a[2] = c;           // 对数组某个元素赋值,正确
a = c;              // a 是数组,不可直接赋值
scanf("%f", &a);    // a 是数组,类型不匹配
printf("%f", a[3]); // a[3] 是float数据,类型不匹配
b[1][2] = a[2];     // 对数组某个元素赋值,正确
b[1] = a;           // b[1] 是数组,不可直接赋值
p = c;              // 类型不匹配
p = a;              // a 代表其首元素地址,等价于p=&a[0],正确

b[1] = a; // b[1] 是数组名,不可直接赋值

2、定义一个二维数组存放用户输入的名单
    char names[10][32]={0};
    printf("\n请输入十个以内名字,单个名字以换行结束,输入以单个名字后加.结束\n");
    int len;
    for (size_t i = 0; i < 10; i++)
    { 
        len=i+1;
        fgets(names[i],32,stdin);
        names[i][strlen(names[i])-1]='\0';
        // printf("输入时:%d\n",names[i][strlen(names[i])-1]);
        if (names[i][strlen(names[i])-1]=='.')
        {
            names[i][strlen(names[i])-1]='\0';
            break;
        }
        
    }
    printf("您输入的名字为:\n");
    for (size_t i = 0; i < len; i++){
        printf("%s ",names[i]);
    }
    printf("\n");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值