C语言笔记之多维数组,字符数组

2  多维数组

2.1 多维数组介绍

下图是一个四行六列的二维数组示意图:

 

2.2 二维数组的定义

1.方式1: 先定义再初始化(最蠢的做法)

// 定义一个4行6列的二维数组
int a[4][6]; 

// 进行初始化赋值
a[0][0] = 10
a[0][1] = 20;
a[0][2] = 30;
a[0][3] = 40;
a[0][4] = 50;
a[0][5] = 60;
a[1][0] = 100;
a[1][1] = 200;
……

2. 方式2: 直接定义并初始化

   

// 定义一个4行6列的二维数组,以为矩阵的形式初始化
int a[4][6] = {
    {10, 20, 30, 30, 40, 60},
    {100, 200, 300, 400, 500, 600},
    {1000, 2000, 3000, 4000, 5000, 6000},
    {10000, 20000, 30000, 40000, 50000, 60000}
};

// 定义一个4行6列的二维数组, 会自动匹配到各行各列
int b[4][6] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};


// 如果所赋值的数量可以与元素数量对应,第一维的数组长度可以不给出
int b[][6] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};

1. 初始化可以不写行但是一定要写列

              2. 如果对全部元素都赋初值(即提供全部初始数据),则定义数组时对第一维的长度可以不指定,但第二维的长度不能省。例如

int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};

与下面定义等价:

int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12};

2.3 二维数组的访问和遍历

        访问二维数组的元素,需要使用两个下标(索引),一个用于访问行(第一维),另一个用于访问列(第二维),我们通常称为行下标(行索引)或列下标(列索引)。遍历二维数组,需要使用双层循环结构

代码示例:

#include <stdio.h>

int main()
{
    // 定义一个 3 行 4 列的数组
    int map[3][4] = {
        {1, 2, 3, 4},
        {11, 12, 13, 14},
        {21, 22, 23, 24}};

    // 计算第一维度的长度
    int rows = sizeof(map) / sizeof(map[0]);
    // 计算第二维度的长度
    int cols = sizeof(map[0]) / sizeof(int);

    // 遍历输出每个元素
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            printf("%d\t", map[i][j]);  // \t 可以输出得更加整齐
        }
        printf("\n");
    }

    // 计算所有元素的和
    int sum = 0;
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            sum += map[i][j];
        }
    }
    printf("所有元素的和:%d", sum); // 所有元素的和:150

    return 0;
}

输出结果:

1       2       3       4
11      12      13      14
21      22      23      24
所有元素的和:150

3.字符数组

3.1字符数组(字符串)介绍

用来存放字符的数组称为字符数组,也可以称为字符串。字符串的输入输出格式占位符是 %s。

        字符串结尾,会自动添加一个 \0 作为字符串结束的标志,所以字符数组最后一个元素必须是 \0。

        \0 是ASCII码表中的第0个字符,用NUL表示,称为空字符,该字符既不能显示,也不是控制字符,输出该字符不会有任何效果,它在C语言中仅作为字符串的结束标志。

3.2 字符数组(字符串)的定义

  1. 方式一:最后一个元素设置成 \0

        在给某个字符数组赋值时,赋值的元素个数小于字符数组的长度,则会自动在后面加 '\0', 表示字符串结束; 赋值的元素的个数等于该数组的长度(或不指定数组长度),则不会自动添加 '\0'。

#include <stdio.h>

int main()
{
    char str1[12] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0'}; // 显式地设值 \0
    char str2[4] = {'t', 'o', 'm'};     // 后面自动添加 \0
    char str3[] = {'j', 'a', 'c', 'k'}; // 不会自动添加 \0

    printf("str1=%s \n", str1); 
    printf("str2=%s \n", str2); 
    printf("str3=%s \n", str3); // 由于没有结束标识,会包括相邻内存的数据,直到遇到结束标记

    return 0;
}

输出结果:

str1=Hello World 
str2=tom
str3=jacktom

2. 方式二:简化写法

#include <stdio.h>

int main()
{
    char str1[] = {"I am happy"}; // 后面自动添加 \0
    char str2[] = "I am happy";   // 省略{}号,后面自动添加 \0

    printf("\n str1=%s", str1);
    printf("\n str2=%s", str2);

    return 0;
}

输出结果:

str1=I am happy
str2=I am happy

3.3 sizeof跟strlen的区别

        strlen用来计算有效字符串的长度,会自动忽略结束字符(’\0’)的长度。sizeof用来计算长度如果用来计算字符串的长度的话会多一个结束字符(’\0’)的长度。

#include <stdio.h>
#include <string.h>	// 定义字符串的头文件

int main()
{
    // 定义字符串
    char greeting[128] = "Hello";  //部分赋值其他部分初始赋值成’\0’

    // 计算字符串长度
    int len = sizeof greeting / sizeof greeting[0];
	int *p = "Hello";
    printf("%s \n", greeting);
printf("数组长度(sizeof):%d \n", sizeof(greeting) );
    printf("数组长度:%d \n", len);
printf("数组长度(strlen):%d \n", strlen(greeting) );
printf("sizeof:p   :%d \n", sizeof(p) );		//相当于sizeof(char *)
printf("strlen):p  :%d \n", strlen(p) );

输出结果:

Hello 
数组长度(sizeof):128
数组长度:128
数组长度(strlen) :5
Sizeof:p     :8;
Strlen:p     :5;

        上文的sizeof(p)sizeof(char *)表达的意思一样,都是表达一个指针所占的几个字节。strlen(p)表达的是字符串的长度。

3.3.几种字符串常用的API

  • 输出字符串
    • puts()
    • printf("%s",p);
  • 获取字符串
    • scanf("%s",p)
    • gets
      • char * gets ( char * str );
      • 因为本函数可以无限读取,易发生溢  出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值
  • 计算长度
    • strlen
  • 拷贝——【拷贝】
    • strcpy
    • char *strcpy(char* dest, const char *src);
    • (strcpy(拷贝输送,拷贝数据))
  • 断言
    • assert——【断言】
  • 拼接
    • strcat
    • char *strcat(char *dest, const char *src);
    • src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除*dest原来末尾的“\0”)。要保证*dest足够长,以容纳被复制进来的*src*src中原有的字符不变。返回指向dest的指针。
  • 拼接
    • Strcat   【拼接】
    •  src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除*dest原来末尾的“\0”)。要保证*dest足够长,以容纳被复制进来的*src*src中原有的字符不变。返回指向dest的指针.
  • 初始化
    • strcmp   【初始化】
      • int strcmp(const char *s1,const char *s2);
        • 若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数
    • strncmp
      • int strncmp ( const char * str1, const char * str2, size_t n )
        • 功能是把 str1 和 str2 进行比较,最多比较前 n 个字节,若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 小于s2,则返回小于0的值。
  • 初始化函数
    • Memset
  • void *memset(void *ptr, int value, size_t num);
  • ptr 是指向要填充的内存块的指针。
  • value 是要填充的值。
  • num 是要填充的字节数。
  • 用于将一块内存按指定的值进行填充。

3.4  动态开辟字符串

  1. malloc 

        函数原型 void *malloc(size_t size)

        含义:C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。

#include <stdio.h>
#include <string.h>	// 定义字符串的头文件
#include <stdlib.h>
int main()
{
	char *p;
	p = (char *)malloc(1);   //开辟一个内存空间让p有了具体的内存指向。
	*p = ‘c’ ;
printf("%c \n", *p);
//输出结果:c
// 同样也可以开辟多个内存空间
	p = (char *)malloc(12);   //开辟12个内存空间让p有了具体的内存指向。
	strcpy(p, "pengkun");
printf("%c \n", *p);
// 输出结果:penkun
return 0;
}

但是此时第一个malloc断开(也就是这个内存是悬挂的无用的,找不到这个地址了)正常情况下像这个无用的内存要给他free掉(因为malloc在堆上开辟空间,数组,普通的变量是在栈上开辟空间,在函数调用结束之后会清理掉这些数据,回收里面的内存。但是堆只有在程序结束后才释放。如果一直循环的话有可能会耗尽堆上的资源)

2. free

C 库函数 void free(void *ptr) 释放之前调用 calloc、malloc 或 realloc 所分配的内存空间

用来释放,防止内存泄漏;防止悬挂指针(野指针的一种·);

#include <stdio.h>
#include <string.h>	// 定义字符串的头文件
#include <stdlib.h>
int main()
{
	char *p;
	p = (char *)malloc(1);   //开辟一个内存空间让p有了具体的内存指向。
	*p = ‘c’ ;
printf("%c \n", *p);
//输出结果:c
// 同样也可以开辟多个内存空间
free(p);  //清除p的内存
	p = (char *)malloc(12);   //开辟12个内存空间让p有了具体的内存指向。
	strcpy(p, "pengkun");
printf("%c \n", *p);
// 输出结果:penkun
return 0;

}

 3. realloc   /   strcpy

        函数原型 void *realloc(void *ptr, size_t size)

        用来扩容:

        C 库函数 void *realloc(void *ptr, size_t size) 尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。

        strcpy(void ptr,“char p”)

用来拷贝,把变量拷贝到ptr中

#include <stdio.h>
#include <string.h>	// 定义字符串的头文件
#include <stdlib.h>
int main()
{
	char *p;
	p = (char *)malloc(1);   //开辟一个内存空间让p有了具体的内存指向。
	*p = ‘c’ ;
printf("%c \n", *p);
//输出结果:c
// 同样也可以开辟多个内存空间
free(p); //清除p的内存
	p = (char *)malloc(12);   //开辟12个内存空间让p有了具体的内存指向。
	int len = strlen("pengkun1234567890");
	int newLen = len - 12 + 1;
	realloc(p, newLen);

	strcpy(p, "pengkun1234567890");   //把pengkun1234567890复制到p中
printf("%s \n", *p);
// 输出结果:penkun
return 0;
}

        不用的话让指针等于NULL,尽量不要让指针成为野指针【29】(链接下文野指针)

也可以加入判断,如果p == NULL则退出程序,exit(-1);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

萌新小白的逆袭

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

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

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

打赏作者

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

抵扣说明:

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

余额充值