前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C语言从青铜到王者——数组详解【一维数组、二维数组、字符数组】

C语言从青铜到王者——数组详解【一维数组、二维数组、字符数组】

原创
作者头像
C语言中文社区
修改2021-05-14 10:13:06
1.5K0
修改2021-05-14 10:13:06
举报
文章被收录于专栏:C语言中文社区C语言中文社区

所谓数组,是指将那些具有相同类型的、数量有限的若干个变量通过有序的方法组织起来的一种便于使用的形式。数组属于一种构造类型,其中的变量被称为数组的元素。数组元素的类型可以是基本数据类型,也可以是特殊类型和构造类型。

一维数组

一位数组是最简单的数组类型,它的定义形式如下:

类型说明符 数组名[常量表达式]

类型说明符是数组中每个元素的类型,常量表达式是数组元素的个数

在使用一维数组的时候需要留意以下两个要点

  • 常量表达式的值必须是正整数
  • 数组元素的引用,数组的起始元素下标为0

下来我们通过一个简单的示例了解一下数组

代码如下:

代码语言:txt
复制
//公众号:C语言中文社区
#include<stdio.h>
#define N 9
int main(void) {
    int arr[N];
    int i;
    for (i = 0; i < N; i++)
    {
        arr[i] = i + 1;
        printf("arr[%d]=%d\t", i, arr[i]);
        if (0 == (i+1)%3)
        {
            printf("\n");
        }
    }
    return 0;
}

运行结果如下:

image
image

我们分析一下上面这段代码

我们定义了一个含有9个元素的一位数组arr,在引用数组中的元素时,采用"数组名下标"的方式,将其中的每一个元素视为一个普通的变量来进行操作。需要注意的是,因为定义的数组arr仅含有9个元素,所以在使用的过程中,下标值不能超过8,否则就会出现下标越界的错误,示例如下:

image
image

在使用数组的时候要特别注意数组越界,不然很有可能为自己埋下一颗雷(bug)。

接下来我们我们通过一段代码看一下数组在内存中是如何存放的

代码语言:txt
复制
//公众号:C语言中文社区
#include<stdio.h>
#define N 4
int main(void) {
    int arr[N];
    int i;
    for (i = 0; i < N; i++)
    {
        arr[i] = i;
        printf("&arr[%d]=%d\n", i, &arr[i]);
    }
    return 0;
}

运行结果如下:

image
image

从结果我们可以看出,每个元素占用4个字节,在内用中的存储结构图如下:

image
image

最后我们再通过一个示例来巩固一下一维数组

需求:使用数组保存用户输入的数据,当输入完毕后逆向输出

代码如下:

代码语言:txt
复制
//公众号:C语言中文社区
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define N 5
int main(void) {
    int arr[N];//定义数组
    int i, temp;//定义变量
    printf("请输入一个5个元素数组:\n");
    for (i = 0; i < N; i++)
    {
        scanf("%d", &arr[i]);
    }
    printf("读取到的数组如下:\n");
    for (i = 0; i < N; i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
    for (i = 0; i < 2; i++)//将数组中元素的前后位置互换
    {
        temp = arr[i];
        arr[i] = arr[4 - i];
        arr[4 - i] = temp;
    }
    printf("输出的逆向数组如下:\n");
    for (i = 0; i < N; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

运行结果如下:

image
image

二维数组

二维数组定义的一般形式如下:

类型说明符 数组名[常量表达式1][常量表达式2]

与一维数组的定义唯一的不同是多了一个常量表达式2,其中,常量表达式1为第一维的长度,常量表达式2为第二维的长度。通常在处理二维数组的时候,为了便于理解,都将数组视为一个矩阵,常量表达式1表示矩阵的行数,而常量表达式2表示矩阵的列数。与一维数组一样,在定义二维数组时,常量表达式同样不能为变量。下面先通过一段代码来看二维数组的定义。

代码语言:txt
复制
//公众号:C语言中文社区
#include<stdio.h>

#define M 4
#define N 3


int main() {
  int arr[M][N];
  for (int i = 0; i < M; i++)
  {
    for (int j = 0; j < N; j++)
    {
      printf("&arr[%d][%d]=%d\t", i, j, &arr[i][j]);
    }
    printf("\n");
  }
  return 0;
}

运行结果:

将二维数组arr视为一个矩阵,下图显示了数组中每个元素在矩阵中的存放位置。

数组中各个元素在矩阵中对应的位置由二维数组的两个下标决定。我们可以将定义的二维数组int arr4视为由arr4和int 3 两部分构成,将arr4视为一个整型一维数组,其中含有4个元素arr0、arr1、arr2、arr3,每个元素都是int3类型的,也就是说,每个元素又是一个一维数组,每个一维数组含有3个元素,如arr0含有arr0、arr0、arr0三个元素。

知道了二维数组的这种特殊结构之后,接下来通过下图来了解二维数组在内存中的存储结构。

通过上述二维数组在内存中的存储结构图可以发现,二维数组中的所有元素都存储在一片连续的内存单元中,所占用的内存大小为元素类型所占用的内存大小乘以第一维及第二维的长度。如果以矩阵的方式来分析二维数组的存储方式,那么先从矩阵第一行从左往右依次存储完所有元素,然后按照同样的方法存储第二行的所有元素,直到存储完所有数组元素为止。

接下来再看一个二维数组的示例:

任意输入一个3行3列的二维数组,求对角元素之和

代码语言:txt
复制
//公众号:C语言中文社区
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

int main() {
  int arr[3][3];
  int i, j, sum = 0;
  printf("please input:\n");
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 3; j++)
    {
      scanf("%d", &arr[i][j]);
    }
  }
  for (i = 0; i < 3; i++)
  {
    for ( j = 0; j < 3; j++)
    {
      if (i==j)
      {
        sum += arr[i][j];
      }
    }
  }
  printf("the result is: %d\n", sum);
  return 0;
}

运行结果如下:

字符数组

字符数组顾名思义就是数组的元素类型为字符型的数组。特殊之处在于它是数组元素为字符的数组。其定义的一般形式和注意事项与之前讲解的一般数组类似,只是其中的类型说明符是char。当然,并不是说类型说明符只能是char,也可以是long、int等,但是由于char型只占用一个字节的大小,使用long型和int型来定义字符数组会造成资源的浪费,因此一般选择使用char型来定义字符数组。

一维字符数组

首先通过下面一段代码来看看一维字符数组的定义。

代码语言:txt
复制
//公众号:C语言中文社区
#include<stdio.h>
#define SIZE 20
int main() {
    long arr1[SIZE] = {'h','e','l','l','o',' ','w','o','r','l','d','!'};
    char arr2[SIZE] = { 'h','e','l','l','o',' ','w','o','r','l','d','!' };
    printf("long型字符数组占用的内存大小为:%d\n", sizeof(arr1));
    printf("char型字符数组占用的内存大小为:%d\n", sizeof(arr2));
    return 0;
}

运行结果:

在上面的代码中定义了不同类型的字符数组来存放相同的字符,可以看出,它们占用的内存大小相差很大,long型字符数组所占用内存大小是char型数组占用内存大小的4倍。从这点可以看出,选用char型作为数组类型避免了内存空间的浪费。下面通过一段代码来了解字符数组的初始化特点。

代码语言:txt
复制
//公众号:C语言中文社区
#include<stdio.h>
#define SIZE 20
int main() {
    int i;
    char arr[SIZE] = { 'h','e','l','l','o',' ','w','o','r','l','d','!' };
    for (i = 0; i < SIZE; i++)
    {
        printf("%c", arr[i]);
    }
    
    return 0;
}

运行结果:

运行结果为“Hello World!”,其中有一些空字符。看看上面代码中定义的arr数组,其数组长度为20,而初始化的字符元素的个数为12,初始化的字符元素个数小于数组长度,编译器在编译过程中将后面没有初始化的数组元素赋值为‘\0’,这也正是打印输出中含有空字符的原因。在打印的时候也可以将数组中的元素‘\0’视为数组结束的标志,例如:

代码语言:txt
复制
//公众号:C语言中文社区
#include<stdio.h>
#define SIZE 20
int main() {
    int i;
    long arr[SIZE] = { 'h','e','l','l','o',' ','w','o','r','l','d','!' };
    for (i = 0; arr[i]!='\0'; i++)
    {
        printf("%c", arr[i]);
    }
    
    return 0;
}

运行结果:

这时的输出结果中就不含有任何空字符了,因为巧妙地使用了字符数组中的‘\0’标志。当然,也可以采用字符串常量的方式来对一维字符数组进行初始化,例如:

代码语言:txt
复制
//公众号:C语言中文社区
#include<stdio.h>
#define SIZE 20
int main() {
    int i;
    char arr[SIZE] = { "hello world!" };
    for (i = 0; arr[i] != '\0'; i++)
    {
        printf("%c", arr[i]);
    }
    
    return 0;
}

运行结果:

在对一维字符数组进行定义和初始化的过程中,可以不指定其长度。使用字符常量列表和字符串常量的方式进行初始化的结果是不同的,例如:

代码语言:txt
复制
//公众号:C语言中文社区
#include<stdio.h>
int main() {
    int i;
    char arr1[] = { "hello world!" };
    char arr2[] = {'h','e','l','l','o',' ','w','o','r','l','d','!'};
    
    printf("采用字符串常量进行初始化的arr1数组的长度为:%d\n", sizeof(arr1));
    printf("采用字符常量列表进行初始化的arr2数组的长度为:%d\n", sizeof(arr2));
    
    return 0;
}

运行结果:

、

从运行结果发现,采用这两种方式得到的数组长度并不相同,在采用字符串常量对字符数组进行初始化的过程中,在内存中进行存储时会自动在字符串的后面添加一个结束符‘\0’,所以得到的字符数组长度是字符串常量的长度加1;而采用字符常量列表的方式对字符数组进行初始化就不会在最后添加一个结束符,所以利用这种方式定义的字符数组的长度就是字符常量列表中字符的个数。

数组实例

交换数组中最大数和最小数的位置

实例代码

代码语言:txt
复制
//
// Created by 冲哥 on 2021/22/09.
// 实现功能:交换数组中最大数和最小数的位置
//
//公众号:C语言中文社区
#include "stdio.h"

int main(){
    int a[10];
    int max, min;
    int m, n;

    printf("请输入10个数字:\n");
    for (int i = 0; i < 10; i++) {
        scanf("%d", &a[i]);
    }
    printf("输入的10个数是:\n");
    for (int i = 0; i < 10; i++) {
        printf("%4d", a[i]);
    }
    printf("\n");
    max = a[0];
    for (int i = 0; i < 10; i++) {
        if (a[i] > max) {
            max = a[i];
            m = i;
        }
    }

    min = a[0];
    for (int i = 0; i < 10; i++) {
        if (a[i] < min) {
            min = a[i];
            n = i;
        }
    }

    a[m] = min;
    a[n] = max;

    printf("交换最大数和最小数的位置后:\n");
    for (int i = 0; i < 10; i++) {
        printf("%4d", a[i]);
    }
} 

运行结果

程序分析

首先找到数组中的最大值和最小值,记录它们的位置,然后交换位置,最后将交换后的数组输出。

更多C语言干货,请微信搜索【C语言中文社区】

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一维数组
  • 二维数组
  • 字符数组
  • 数组实例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档