当前位置: 首页 > article >正文

C语言基础16:二维数组、字符数组

二维数组

定义

二维数组本质上是一个行列式的组合,也就是说二维数组由行和列两部分组成。属于多维数组,二维数组数据是通过行列进行解读。

二维数组可被视为一个特殊的一维数组,相当于二维数组又是一个一维数组,只不过它的元素是一维数组。(也就是说数组的元素的类型可以是数组类型)

语法
数据类型 数组名 [行数][列数];//二维数组外层表示行数,内层表示列数

举例:

int arr[3][3] = {{11,22,33},{21,22,23},{31,32,33}};//正确,等价于下面写法
int arr[][3] = {{11,22,33},{21,22,23},{31,32,33}}; //正确广义上称之为柔性数组

int arr[3][3] = {{11,12},{21,22,23},{31}};  //正确,等价于下面写法
int arr[3][3] = {{11,12,0},{21,22,23},{31,0,0}};//正确

int arr[3][3] = {};//正确,全部为0
int arr[3][3] = {{11}};//正确,未初始化的元素使用0填充

int arr[][] = {{11,22,33},{21,22,23},{31,32,33}};//这种写法会编译错误,不能省略
int arr[3][] = {{11,22,33},{21,22,23},{31,32,33}};//这种写法会编译错误,不能省略

注意:在C语言中,二维数组在计算机的存储顺序是按行进行的,即第一维的下标变化慢,第二维的下标变化快。

应用场合

主要应用于数据有行列要求的情况。比如说我们现在要存储班级的学生的成绩。

特殊写法
  • 下标可以是整型表达式,如:a[2-1][2*2-1]
  • 下标可以是已经有值的变量或数组元素,如:a[2*x-1]
  • 数据元素可以出现在表达式中,如:b[1][2] = a[2][3]/2
  • 注意:使用数组元素的下标应在已定义数组的大小范围内:应注意区别定义数组大小和引用数组元素的区别。
初始化
  • 分行给二维数组赋初值

    int arr[3][4] = {{11,12,13,14},{21,22,23,24},{31,32,33,34}};
    
  • 可将所有数据写在一个花括号内,按照排列顺序对元素赋值

    int arr[3][4] = {11,12,13,14,21,22,23,24,31,32,33,34};
    
  • 可对部分元素赋初值,其余未赋值部分自动填充 整型默认值-0 | 字符型默认值-\0 | 浮点型默认值-0.0..

    int arr[3][4] = {{11},{21,22},{31}};
    
  • 若对全部元素赋初值,自定义数组时可以省略第1维数组的长度,第2维数组的长度必须指明。

    int a[][4] = {11,12,13,14,21,22,23,24,31,32,33,34};
    
  • 在分行赋初值时,也可以省略第1维的长度。

    int arr[][4] = {{11,12,13},{0},{0,10}};
    
案例

案例1:

  • 需求:二维数组的遍历

  • 代码:

    /*************************************************************************
      > File Name:    demo01.c
      > Author:       ZK
      > Description:二维数组的遍历  
      > Created Time: 2025年02月17日 星期一 09时15分14秒
     ************************************************************************/
    
    #include <stdio.h>
    
    int main(int argc,char *argv[])
    {
        //创建一个二维数组,必须指定列
        int arr[][3] = {{11},{21,22},{31,32,33}};
    
        //获取二维数组的大小
        int r_len = sizeof(arr) / sizeof(arr[0]);
    
        //遍历二维数组
        //外层循环,遍历行元素(行元素是数组类型)
        for(int row = 0;row < r_len; row++)
        {
            //内层循环,遍历列元素(列元素是单一类型)
            int c_len = sizeof(arr[row]) / sizeof(int);
            //内层循环,遍历列元素(列元素时是单一类型)
            for(int col = 0; col < c_len; col++)
            {
                //获取元素
                printf("%-3d",arr[row][col]);
            }
        }
    
        printf("\n");
    
        return 0;
    }
    
    
  • 运行结果:

    在这里插入图片描述

案例2:

  • 需求:矩阵的转置(将一个2行3列的数组转换为3行2列的数组)

  • 代码:

    /*************************************************************************
      > File Name:    demo02.c
      > Author:       ZK
      > Description:二维数组的转置
      > Created Time: 2025年02月17日 星期一 09时39分39秒
     ************************************************************************/
    
    #include <stdio.h>
    
    //定义行和列
    #define ROW 2
    #define COL 3
    
    int main(int argc,char *argv[])
    {
        //准备2个数组用来存放转置前后的数列
        int arr_before[ROW][COL] = {{11,12,13},{14,15,16}};
        int arr_after[COL][ROW] = {0};
    
        //计算arr_before的大小
        int r_len = sizeof(arr_before) / sizeof(arr_before[0]);
    
        //遍历
        for(int i = 0; i < r_len; i++)
        {
            //计算arr_before中的列数
            int c_len = sizeof(arr_before[i]) / sizeof(int);
            for (int j = 0; j < c_len; j++ )
            {
                printf("%-4d",arr_before[i][j]);
    
                //转置
                arr_after[j][i] = arr_before[i][j];
            }
            printf("\n");
    
        }
    
        printf("\n");//换行
        
        //循环输出arr_after
        for(int i = 0;i < sizeof(arr_after)/sizeof(arr_after[0]); i++)
        {
            for(int j = 0;j < sizeof(arr_after[i])/sizeof(int);j++)
            {
                printf("%-4d",arr_after[i][j]);
            }
    
            printf("\n");
        }
    
        return 0;
    }
    
    
  • 运行结果:

在这里插入图片描述

字符数组

概念

元素类型为char字符型的数组,字符数组往往是用来存储字符串数据的。需要注意的一点是,我们C语言中的字符是字节字符。

字节字符:也就是一个字符占1个字节,在C语言中,我们使用char表示字节。

举例:

char a = 'A';	//正确
char b = '1';	//正确
char c = 65;	//正确。char支持两种赋值形式,一种是字符,一种是赋值,如果是数值表示ASCII码
char d = "A";	//错误,char字符不能使用双引号
char e = '卜';	//错误,中文一个字符超过了一个char

C语言支持字符串常量,不支持字符串变量

语法
char 数组名[容量];
char 数组名[行容量][列容量];

字符数组的语法就是我们前面所学的一维数组和二维数组的语法,只不过数组的数据类型是char而已。

注意:

​ 如果我们的char数组初始化的时候,没有完全初始化值的时候,空出来的地方使用\0进行填充。大家要注意,这里的\0只起到占位的作用,我们是无法通过printf进行输出的。

比如:

char c[8] = {'h','e','l','l','o'};//等价于
char c[8] = {'h','e','l','l','o','\0','\0','\0'};
案例

案例1:

  • 需求:输出一个字符序列(I LOVE YOU!)

  • 代码:

    /*************************************************************************
      > File Name:    demo03.c
      > Author:       ZK
      > Description:字符数组案例 
      > Created Time: 2025年02月17日 星期一 10时43分10秒
     ************************************************************************/
    
    #include <stdio.h>
    
    int main(int argc,char *argv[])
    {
        //创建一个数组用来存储I LOVE YOU ASCII中32对应空格
        char arr[10] = {'I',' ','L','O','V','E',' ','Y','O','U'};
        
        //使用for遍历数组
        for(int i = 0;i < sizeof(arr) / sizeof(char);i++)
        {
            printf("%c",arr[i]);
        }
    
        printf("\n");
    
        return 0;
    }
    
    
  • 运行结果:

在这里插入图片描述

案例2:

  • 需求:输出一个用字符组成的菱形图案

  • 代码:

    /*************************************************************************
    > File Name:demo04.c
    > Author:ZK
    > Description:
    > Created Time: 2025年02月17日 星期一 10时50分33秒
    ************************************************************************/
    
    #include <stdio.h>
    
    int main(int argc,char *argv[])
    {
        // 准备数据
        char arr[5][5] = {
            {' ',' ','*',' ',' '},
            {' ','*','*','*',' '},
            {'*','*','*','*','*'},
            {' ','*','*','*',' '},
            {' ',' ','*',' ',' '}
        };
        
        // 遍历数组
        for (int i = 0;i < sizeof(arr)/sizeof(arr[0]); i++)
        {
            for (int j = 0; j < sizeof(arr[i])/sizeof(char); j++)
            {
                printf("%c",arr[i][j]);
            }
            printf("\n");
        }
        printf("\n");
        
        return 0;
    }
    
    

注意:

①如果定义时,不初始化,元素值不确定

char arr1[2];	//此时属于未初始化,元素的值不确定(随机值),大概率是\0.也有可能是其值。
char arr2[5] = {'a','b','c'};//此时属于不完全初始化,未初始化的元素使用\0进行填充

②如果提供的字符个数大于数组长度,则按照语法错误处理;如果字符个数小于数组长度,后面的元素自动为空字符(\0)

③如果提供的字符个数与数组长度相同,可以省略数组长度,系统会自动确定元素个数,适合字符较多时。

字符串结束标志
说明
  • C语言规定,字符串以字符'\0'作为结束标志。

  • 编译系统对字符串常量自动加一个\0作为结束标志。

  • 程序中往往通过判断\0来检测字符串是否结束。

  • \0的ASCII码是0,不是一个可显示的字符,是“空操作符”,它什么都不做,不会增加有效字符,仅是一个工程判别的标志。

    char c[] = {'h','i'};//字符数组	hi
    char c[] = {'h','i','\0'};//字符串	hi
    char c[] = "hello";//实际等价于 hello\0
    
    // \0(空字符),ASCII码是0
    // 0 , ASCII码是48
    // 空格,ASCII码是32
    
字符数组的多样表示

我们的char数组可以以数组的形式一个个输出每个字符;我们的char数组也可以以字符串的方式整体进行输出所有字符。

案例:

/*************************************************************************
> File Name:demo05.c
> Author:ZK
> Description:
> Created Time: 2025年02月17日 星期一 11时24分19秒
************************************************************************/

#include <stdio.h>

int main(int argc,char *argv[])
{
    // 字符串的第1种表示:
    char s1[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'};
    // 字符串的第2种表示:
    char s2[] = {"hello world"};// 字符串常量默认以\0结尾
    // 字符串的第3种表示:
    char s3[] = "hello world";
    
    // 输出字符串
    printf("%s\n%s\n%s\n",s1,s2,s3);
    
    return 0;
}

注意:

  • 字符串的长度与字符数组的长度不一定相同。
  • 利用字符串常量可以对字符数组进行初始化,但不能用字符串常量对字符数组赋值。
// 正确演示:利用字符串常量给字符数组初始化
char arr1[6] = "hello";

// 错误演示:用字符串常量为字符数组赋值
char arr2[6];
arr2 = "hello";
字符串的基础操作

在用格式化说明符%s进行输入输出时,其输入输出项均为数组名、但在输入时,相邻两个字符串之间要用空格分隔,系统将自动在字符串最后加上\0,在输入时,遇到结束符\0作为输出结束标志。

对于字符串操作,我们需要使用到一些系统提供的函数(API操作)。

字符串输入
scanf

语法:

scanf("%s",&数组名);

注意:数组名对应的数组只能是char类型

案例:

/*************************************************************************
> File Name:demo06.c
> Author:ZK
> Description: 字符串输入函数:scanf
> Created Time: 2025年02月17日 星期一 15时26分41秒
************************************************************************/

#include <stdio.h>

int main(int argc,char *argv[])
{
    // 创建一个数组,用来存放人的名字
    char name[20];
    
    printf("请输入您的名字:\n");
    scanf("%s",name);// scanf第二个参数需要传递变量地址,如果是数组,数组名就代表数组的首地址,因为数组本身是没有空间的,其空间就是元素空间
    printf("您的姓名是%s\n",name);
    return 0;
}

注意:采用scanf()进行字符串输入,要求字符串中不能存在空格,否则字符串遇到空格就会结束。

fgets

语法:

fgets(数组名,数组容量,stdin);

功能:
从键盘录入一个字符串常量到字符数组,返回字符数组的地址(首地址,默认返回的地址,一般用12位16进制数表示)

说明:

​ 采用fgets进行字符串输入,可获取所有输入的字符串,包含 \n ,在实际的字符串处理时,我们可能需要处理 \n

案例:

/*************************************************************************
> File Name:demo06.c
> Author:ZK
> Description: 字符串输入函数:fgets
> Created Time: 2025年02月17日 星期一 15时26分41秒
************************************************************************/

#include <stdio.h>

int main(int argc,char *argv[])
{
    // 创建一个数组,用来存放人的名字
    char name[20];
    
    printf("请输入您的名字:\n");
    // fgets和scanf只能二选一
    fgets(name,sizeof(name)/sizeof(name[0]),stdin);
    printf("您的姓名是%s\n",name);
    return 0;
}  

注意:
① 如果输入的字符串不包括 空格 或 换行,可以使用scanf |fgets

​ ② 如果输入的字符串需要包含 空格 或 换行,只能使用fgets

​ ③ 经过对比,我们发现,在字符串输入中,fgets和scanf相比,fgets友好一些

gets 危险的

语法:

gets(数组名);

功能:
从键盘录入一个字符串常量到字符数组,返回字符数组的地址(首地址,默认返回的地址,一般用12位16进制数表示)

说明:

​ 采用gets进行字符串输入,可获取所有输入的字符串,包含 \n ,在实际的字符串处理时,我们可能需要处理 \n

案例:

/*************************************************************************
> File Name:demo06.c
> Author:ZK
> Description: 字符串输入函数:fgets
> Created Time: 2025年02月17日 星期一 15时26分41秒
************************************************************************/

#include <stdio.h>

int main(int argc,char *argv[])
{
    // 创建一个数组,用来存放人的名字
    char name[20];
    printf("请输入您的名字:\n");
    // fgets和scanf只能二选一
    fgets(name,sizeof(name)/sizeof(name[0]),stdin);
    printf("您的姓名是%s\n",name);
    
    return 0;
}

字符串输出
printf

语法:

printf("%s",数组名);

案例:

/*************************************************************************
> File Name:demo06.c
> Author:ZK
> Description: 字符串输入函数:scanf
> Created Time: 2025年02月17日 星期一 15时26分41秒
************************************************************************/

#include <stdio.h>

int main(int argc,char *argv[])
{
    // 创建一个数组,用来存放人的名字
    char name[20];
    
    printf("请输入您的名字:\n");
    scanf("%s",name);// scanf第二个参数需要传递变量地址,如果是数组,数组名就代表数组的首地址,因为数组本身是没有空间的,其空间就是元素空间
    printf("您的姓名是%s\n",name);
    return 0;
}

fputs

语法:

fputs(const char *s,FILE *stream);

功能:

​ 输出一个字符串

说明:

​ 字符串可以包含转义字符

案例:

/*************************************************************************
> File Name:demo06.c
> Author:ZK
> Description: 字符串输入函数:fputs()
> Created Time: 2025年02月17日 星期一 15时26分41秒
************************************************************************/

#include <stdio.h>

int main(int argc,char *argv[])
{
    // 创建一个数组,用来存放人的名字
    char name[20];
    
    printf("请输入您的名字:\n");
    // gets、fgets和scanf只能多选一
    gets(name);
    
    // 输出
    fputs(name,stdout);// 标准的输出
    return 0;
}

puts

语法:

puts(const char *s);

功能:

​ 输出一个字符串

说明:

​ 字符串可以包含转义字符

案例:

/*************************************************************************
> File Name:demo06.c
> Author:ZK
> Description: 字符串输入函数:fputs()
> Created Time: 2025年02月17日 星期一 15时26分41秒
************************************************************************/

#include <stdio.h>

int main(int argc,char *argv[])
{
    // 创建一个数组,用来存放人的名字
    char name[20];

    printf("请输入您的名字:\n");
    // gets、fgets和scanf只能多选一
    gets(name);

    // 输出
    puts(name);// 标准的输出
    return 0;
}

字符串转数值
  • strtol

    long strtol(const char *str, char **endptr, int base);
    

    将字符串转换为长整型数。

    参数说明:

    • str :指向要转换的字符串的指针。
    • endptr :一个指向字符指针的指针。如果提供了这个参数,并且转换成功, *endptr 将被设置为指向第一个未转换字符的指针。如果 endptr NULL ,则不使用它。
    • base :用于指定转换的基数。它可以是 2 到 36 之间的值,或者是特殊值 0。如果 base是 0,则函数会根据字符串的前缀(如 “0x” 或 “0X” 表示十六进制,“0” 表示八进制,否则默认为十进制)来自动确定基数。
  • strtoul

    unsigned long strtoul(const char *str, char **endptr, int base);
    

    将字符串转换为无符号长整型数。

  • strtod

    double strtod(const char *str, char **endptr);
    

    将字符串转换为双精度浮点数。

  • atoi

    int atoi(const char *str);
    

    将字符串转换为整型数(不推荐使用,建议使用 strtol )。

  • atol

    long atol(const char *str);
    

    将字符串转换为长整型数(不推荐使用,建议使用 strtol )。

  • atof

    double atof(const char *str);
    

    将字符串转换为双精度浮点数(不推荐使用,建议使用 strtod )。

案例:

/*************************************************************************
> File Name:demo09.c
> Author:ZK
> Description: 字符串转换数值
> Created Time: 2025年02月17日 星期一 16时20分34秒
************************************************************************/

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char *argv[])
{
	printf("%lo,%ld,%lx\n",strtol("12",NULL,8),strtol("12",NULL,10),strtol("12",NULL,16));
    printf("%lo,%ld,%lx\n",strtol("012",NULL,0),strtol("12",NULL,10),strtol("0x12",NULL,0));
    
    int a = 10;
    
    printf("%p,%lx\n",&a,&a);
    return 0;
}


http://www.kler.cn/a/550288.html

相关文章:

  • Mac本地部署deepseek
  • uv 简易安装与更换国内镜像源
  • 网页制作02-html,css,javascript初认识のhtml的文字与段落标记
  • Groovy语言的学习路线
  • Leetcode 227-基本计算器 II
  • MFC 自定义十六进制显示控件
  • CSDN、markdown环境下如何插入各种图(流程图,时序图,甘特图)
  • 玩转大语言模型——使用LM Studio在本地部署deepseek R1的零基础)教程
  • 深入理解Python多进程编程 multiprocessing
  • Vue 3 中,Pinia 和 Vuex 的主要区别
  • 珈和科技产品矩阵实现deepseek大模型能力接入 构建AI多模态农业大模型赋能农业提质增效
  • 蓝桥杯小白打卡第五天
  • llama.cpp部署 DeepSeek-R1 模型
  • Delphi语言的软件工程
  • 从宇树科技机器人 G1 爆火,看机器人发展现状与未来
  • Vue 状态管理
  • Linux(centos)系统安装部署MySQL8.0数据库(GLIBC版本)
  • Java 开发者需要了解的 PDF 基础知识
  • 矩阵碰一碰发视频源码源头搭建,支持OEM
  • pytest测试专题 - 1.3 测试用例发现规则