首页 > 编程语言 >衡庐浅析·C语言程序设计·第四章·数组

衡庐浅析·C语言程序设计·第四章·数组

时间:2024-08-03 09:52:40浏览次数:17  
标签:初始化 arrayName int 元素 C语言 衡庐 数组 字符串 浅析

       本文适用于大学的期中期末考试、专升本(专接本、专插本)考试、408等考研预科。如有相关题目疑问或建议欢迎在评论区进行互动。

       转载请标明出处。


在深入学习C语言的数组之前,我们先回顾一下C语言的三大基本结构:顺序结构、选择结构和循环结构。这些结构构成了编程逻辑的基础,让我们能够编写出功能丰富、逻辑清晰的程序。

顺序结构保证了程序按照代码的书写顺序执行;选择结构(如 if 语句和 switch 语句)让我们能够根据不同的条件执行不同的代码分支;循环结构(如 forwhiledo...while 循环)允许我们重复执行一段代码,直到满足特定的退出条件。

现在,当我们对这些基本结构有了深刻的理解之后,我们可以迈向C语言中另一个强大的特性——数组。

数组是存储固定大小的同类型元素的集合,它使得数据的批量处理和管理变得简单高效。

数组作为C语言中一个核心的数据结构,它不仅能够存储一系列的数据,还允许我们通过索引快速访问和修改这些数据。无论是对数据进行排序、搜索还是变换,数组都提供了一种高效且直接的手段。

一维数组

在开头我们提到,数组是存储固定大小的同类型元素的集合。其中一维数组是数组的基本形式,具有连续的内存空间。

它们通常使用以下语法定义:

type arrayName[length];

/*  type 是数据类型,如 int, float, char 等。
arrayName 是数组的名称。
length 是数组可以存储的元素数量。  */

其中的 length 我们也将其称之为数组下标,在C语言中,我们规定:

数组的下标从0开始

值得注意的是: 

数组名 arrayName 不是变量,是数组元素存储的首地址,故为常量

arrayName[length] 是变量

由于 arrayName 是常量,故在定义初始化后只能一个一个赋值

(在字符数组中有另外两种定义后整体赋值的方法,在后面内容中会有所介绍)

举个例子:

a = {1, 2, 3, 4, 5};  //错误!不能整体赋值,只能逐一赋值

a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5;  //正确!

数组的初始化是指在定义数组的同时对数组元素进行赋值,通常有以下两种类型:

  1. 静态初始化:
    type arrayName[length] = {value1, value2, ...};

    静态初始化不仅能对所有元素进行依次赋值,也可以只对部分元素赋值,但对于没有赋值的元素默认赋值为0(部分元素赋值后未赋值的才为0,若未进行赋值操作未赋值的为随机数)。

  2. 动态初始化:
    type arrayName[length];
    for (int i = 0; i < length; i++)
    {
        arrayName[i] = someValue;
    }

    利用循环、函数、指针等方式进行赋值。

在C语言中,允许初始化数组时省略长度,其默认长度及为数组元素总和。

如果我们需要访问数组的元素,通常需要使用索引,索引从0开始:

element = arrayName[index];

/*  element 是数组中的一个元素。
index 是元素的索引。  */

其边界为:

  • 上界:arrayName[length - 1]
  • 下界:arrayName[0]

而遍历数组的所有元素可以使用循环结构:

for (int i = 0; i < length; i++)
{
    //使用 arrayName[i] 访问或修改元素
}

其内存分配常常遵循以下规则:

  • 数组在栈上分配内存,创建时分配固定大小。
  • 数组的内存地址是连续的。

对于数组的特点,我们可以简略的总结如下:

  • 优点:访问速度快,内存连续,易于遍历。
  • 缺点:大小固定,一旦声明不能改变。

这里举一个一维数组的经典例子:

#include <stdio.h>

// 函数声明
void printArray(int arr[], int size);

int main()
{
    int numbers[5]; // 声明一个整型数组,可以存储5个元素
    int i;

    // 手动初始化数组
    numbers[0] = 10;
    numbers[1] = 20;
    numbers[2] = 30;
    numbers[3] = 40;
    numbers[4] = 50;

    // 打印数组元素
    printf("手动初始化的数组元素:\n");
    for (i = 0; i < 5; i++)
    {
        printf("%d ", numbers[i]);
    }
    printf("\n");

    // 使用函数打印数组
    printArray(numbers, 5);

    return 0;
}

// 函数定义
void printArray(int arr[], int size)
{
    int i;
    printf("数组内容: ");
    for (i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

代码解析:

  1. 数组声明:在 main 函数中,声明了一个名为 numbers 的整型数组,它可以存储5个整数。

  2. 手动初始化:通过直接指定索引值的方式,对数组的每个元素进行初始化。

  3. 遍历数组:使用一个 for 循环遍历 numbers 数组,并使用 printf 函数打印每个元素的值。

  4. 函数 printArray:定义了一个接受整型数组和数组大小为参数的函数,用于打印数组的所有元素。函数内部同样使用 for 循环遍历数组。

  5. 函数调用:在 main 函数中调用 printArray 函数,并传入 numbers 数组及其大小,演示了如何将数组作为参数传递给函数。

二维数组

二维数组在C语言中可以看作是数组的数组,通常用于存储矩阵或表格数据。它可以用直角坐标系中的行和列来理解。

其定义语法如下:

type arrayName[rowSize][columnSize];

其中: 

  • type 是数据类型(如 intfloatchar 等)。
  • arrayName 是数组的名称。
  • rowSize 是数组的行数。
  • columnSize 是数组的列数。

类似的,arrayName 在题目中也简略的写为 arr 或 a 。

数组名不是变量,同样也是地址常量。

它的初始化同样分为两种,即静态初始话与动态初始化:

  1. 静态初始化:
    type arrayName[rowSize][columnSize] =
    {
        {v11, v12, ..., v1n},
        {v21, v22, ..., v2n},
        ...
        {vm1, vm2, ..., vmn}
    };
  2. 动态初始化:
    type arrayName[rowSize][columnSize];
    for (int i = 0; i < rowSize; i++)
    {
        for (int j = 0; j < columnSize; j++)
        {
            arrayName[i][j] = someValue;
        }
    }

需要补充记忆的是以下两点:

C语言按行优先。

在初始化中,允许省略第一维(行)的长度,但不允许省略第二维(列)的长度。

通过这几个例子可以清晰的理解体会:

int a[2][3] = {{1,2,3},{4,5,6}};

//第一行的元素为 1,2,3, 第二行的元素为 4,5,6
int a[2][3] = {1,2,3,4,5,6};

//按行优先,第一行的元素为 1,2,3,第二行的元素为4,5,6
int a[2][3] = {{1},{2,3}};

//第一行的元素为1,0,0, 第二行的元素为2,3,0
int a[2][3] = {1,2,3};

//第一行的元素为1,2,3, 第二行的元素为 0,0,0
int a[][3] ={1,2,3,4,5,6};

//这里有6个元素,每行3列,故默认第一维的长度为2;
//第一行的元素为1,2, 第二行的元素为 3,4,第三行的元素为 5,6

对于访问二维数组元素,同样使用以下方法:

element = arrayName[row][column];

其中:

  • element 是数组中的一个元素。
  • row 是元素的行索引。
  • column 是元素的列索引。

二维数组的边界即确保索引在有效的范围内:0 <= i < rowSize 且 0 <= j < columnSize

对于二维数组的遍历,使用嵌套循环即可遍历其所有元素:

for (int i = 0; i < rowSize; i++)
{
    for (int j = 0; j < columnSize; j++)
    {
        //使用 arrayName[i][j] 访问或修改元素
    }
}

其内存分配如下: 

  • 二维数组通常在栈上分配内存,内存是连续的。
  • 行连续,但每行的列可能不连续,取决于每个元素的类型。

举一个经典的二维数组例子:

#include <stdio.h>

int main()
{
    int rows = 3;       // 定义数组的行数
    int columns = 4;    // 定义数组的列数
    int myArray[rows][columns]; // 声明一个3x4的二维数组

    // 初始化二维数组
    for (int i = 0; i < rows; i++) 
    {
        for (int j = 0; j < columns; j++) 
        {
            myArray[i][j] = i * columns + j + 1;  // 赋值示例:(i, j)位置的元素值为(i*4 + j + 1)
        }
    }

    // 打印二维数组
    printf("二维数组内容:\n");
    for (int i = 0; i < rows; i++) 
    {
        for (int j = 0; j < columns; j++) 
        {
            printf("%d ", myArray[i][j]);
        }
        printf("\n");
    }

    // 修改特定元素
    myArray[1][2] = 999; // 将第二行第三列的元素修改为999

    // 再次打印二维数组,展示修改结果
    printf("修改后的二维数组内容:\n");
    for (int i = 0; i < rows; i++) 
    {
        for (int j = 0; j < columns; j++) 
        {
            printf("%d ", myArray[i][j]);
        }
        printf("\n");
    }

    return 0;
}

代码解析:

  1. 数组声明:声明了一个名为 myArray 的整型二维数组,具有3行4列。

  2. 初始化二维数组:使用嵌套的 for 循环对数组进行初始化。循环中的 i 代表行索引,j 代表列索引。

  3. 打印二维数组:首先打印初始化后的二维数组内容,使用嵌套的 for 循环遍历数组并打印每个元素。

  4. 修改元素:通过指定索引的方式,修改了数组中第二行第三列的元素值为999。

  5. 再次打印数组:修改元素后,再次打印整个数组,展示修改的结果。

字符数组

在学习字符数组之前,我们先需要了解一个概念:

C语言没有字符串类型,字符串是存放在字符数组中的。

所以,字符数组在C语言中是用来存储字符数据的数组。它通常用于处理字符串,即字符的集合。

它的定义语法如下:

char arrayName[length];

其中:

  • char 表示数组存储的是字符数据。
  • arrayName 是数组的名称。
  • length 是数组可以存储的字符数量。

其初始化类似于一维、二维数组,分为以下两种:

  1. 静态初始化(字符串字面量):
    char arrayName[] = "Hello, World!";
  2. 动态初始化:
    char arrayName[20];
    for (int i = 0; i < 12; i++)
    {
        arrayName[i] = 'H' + (i % 2); // 例如初始化为 "HhHhHhHhHh"
    }

它使用索引访问或修改数组元素:

char element = arrayName[index];
arrayName[index] = 'a'; // 修改特定索引的字符

其中:

  • element 是数组中的一个字符。
  • index 是字符的索引。

对于其中常用字符串操作函数,我们留到下一个章节单独进行详细介绍,这里仅列出部分简介。

C语言标准库 <cstring> 提供了多个用于操作字符数组的函数,如:

  • strcpy():复制字符串。
  • strcat():连接字符串。
  • strlen():计算字符串长度,不包括结束的空字符。
  • strcmp():比较两个字符串。
  • strchr():查找字符串中首次出现某个字符的位置。
  • getchar():字符输入函数。
  • putchar():字符输出函数。
  • gets():字符串输入函数。
  • puts():字符串输出函数。

在C语言中,字符数组经常用来表示字符串,但它们不是同一个概念:

  • 字符数组是一个存储字符的固定大小的数组。
  • 字符串是一个以空字符('\0')结尾的字符数组。

C语言字符串以空字符('\0')结尾,用于表示字符串结束。

举个例子:

char string[] = "Hello";
string[5] = '\0'; // 手动添加字符串结束标志

 举一个经典的字符数组的例子:

#include <stdio.h>
#include <string.h>

// 函数声明
void printReversed(const char str[]);

int main()
{
    char myString[50]; // 声明一个字符数组,用于存储字符串

    // 请求用户输入一个字符串
    printf("请输入一个字符串:");
    fgets(myString, sizeof(myString), stdin); // 使用fgets来读取一行文本

    // 去除可能读取到的换行符
    size_t len = strlen(myString);
    if(len > 0 && myString[len - 1] == '\n') 
    {
        myString[len - 1] = '\0';
    }

    // 打印原始字符串
    printf("原始字符串: %s\n", myString);

    // 调用函数,打印反转后的字符串
    printf("反转后的字符串: ");
    printReversed(myString);
    printf("\n");

    return 0;
}

// 函数定义:打印字符串的反转
void printReversed(const char str[]) 
{
    int len = strlen(str);
    for (int i = len - 1; i >= 0; i--) 
    {
        putchar(str[i]);
    }
}

代码解析:

  1. 字符数组声明:在 main 函数中,声明了一个名为 myString 的字符数组,预定义了大小为50。

  2. 用户输入:使用 fgets 函数读取用户输入的一行文本,包括空格,存储在 myString 中。

  3. 去除换行符:fgets 会将换行符也读取到字符串中,通过检查字符串的最后一个字符并将其替换为字符串结束符 \0 来去除它。

  4. 打印原始字符串:使用 printf 函数打印用户输入的原始字符串。

  5. 字符串反转:定义了一个 printReversed 函数,它接收一个字符数组作为参数,并使用一个 for 循环从后向前打印每个字符,实现字符串的反转。

  6. 调用函数:在 main 函数中调用 printReversed 函数,并传入 myString,打印反转后的字符串。


《衡庐浅析·C语言程序设计·第四章·数组》部分到这里就结束了,我会在后续章节编写一些题目或分享一些典型的例子以巩固所学的知识点。下一个知识点章节我们将会学习C语言中函数的相关知识,敬请期待,也欢迎大家在评论区进行互动!

标签:初始化,arrayName,int,元素,C语言,衡庐,数组,字符串,浅析
From: https://blog.csdn.net/m0_68962556/article/details/140746505

相关文章

  • c语言位运算符和位运算,位运算举例,位段
    位运算符1.按位与运算符(&)按位与运算符对两个整数的每一位进行“与”操作,只有当两个位都是1时,结果才为1,否则为0。inta=5; //二进制:00000101intb=3; //二进制:00000011intresult=a&b; //结果:00000001(1)2.按位或运算符(|)按位或运算符对......
  • 【C语言】操作符详解
    目录一、操作符分类二、移位操作符(1)左移位操作符(2)右移位操作符三、位操作符四、移位、位操作符的综合练习(1)不用临时变量,交换两个整数(2)求内存中整数的二进制中1的个数(3)二进制位置0或置1五、单目操作符六、逗号表达式七、结构体成员访问操作符(1)结构体(2)结构体的声明......
  • C语言——函数
    C语言——函数函数的语法函数的调用关系递归函数的主要思想是:函数其实是从上到下逐步求解的过程,把一个大的问题拆成多个小的子问题或者说把一个大的功能拆成小的功能模块,通过实现小的功能最终实现大的功能的过程。函数的语法类型标识符函数名(形式参数){函数体......
  • 【C语言】程序环境,预处理,编译,汇编,链接详细介绍,其中预处理阶段重点讲解
    目录程序环境翻译环境1.翻译环境的两个过程2.编译过程的三个阶段 执行环境 预处理(预编译) 1.预定义符号2.#define 2.1用#define定义标识符(符号)2.2用#define定义宏 2.3#define的替换规则 2.4#和##的用法2.5宏和函数2.6#undef3.命令......
  • C语言指针与数组
    在上一篇对指针介绍的文章当中,我们初次了解到了指针,并且知道了地址和内存间的关系,懂得了如何取地址和对指针的解引用,算是对指针有了一个初步的了解。而今天让我们对指针进行更深一步的了解吧~一、指针与数组名我们知道,指针变量是一个用来存放地址的变量,比如我们定义一个整形......
  • 嵌入式软件--C语言高级 DAY 8.5 相关函数
    递归函数在嵌入式中应用不常见,但对于学习C语言的我们,也要时刻记得它的作用和用法。此外还要记住sprintf尤其重要!还有时间戳!一、递归函数1.概念一个函数在函数体内又调用了本身。但必须满足两个条件:具有明显的结束条件;趋近于结束条件的趋势。2.递归原理#include<stdio.h>......
  • 嵌入式软件--C语言高级 DAY 7数组
    一、概念数组array:是多个相同类型数据按一定顺序排列的集合,并使用一个标识符命名。并通过编号(索引,亦称为下标或角标)的方式对这些数据进行统一管理。数组的长度=元素的个数标号角标是从0开始。二、define_array.c定义数组的三种形式:1.定义数组,可以先确定数组的元素个......
  • C语言数据在内存中的存储超详解
    文章目录1.整数在内存中的存储2.大小端字节序和字节序判断2.1什么是大小端?2.2为什么会有大小端?2.3练习3.浮点数在内存中的存储3.1一个代码3.2浮点数的存储3.2.1浮点数存的过程3.2.2浮点数取的过程3.3题目解析1.整数在内存中的存储在操作符......
  • C语言自定义类型结构体与位段超详解
    文章目录1.结构体类型的声明1.1结构体声明1.2结构体变量的创建和初始化1.3结构体的特殊声明1.3结构体的自引用2.结构体内存对齐2.1对齐规则2.2为什么存在内存对齐2.3修改默认对齐数3.结构体传参4.结构体实现位段4.1什么是位段4.2位段成员的内存......
  • c语言中的地址与指针的概念,及变量的指针和指向变量的指针变量
    C语言中的地址、指针、以及变量的指针与指向变量的指针变量。1.地址(Address)在C语言中,每个变量在内存中都有一个唯一的内存地址。这个地址是变量存储的位置的标识符。可以通过& 运算符来获取一个变量的地址。#include<stdio.h>intmain(){  intx=10;  ......