Bootstrap

C语言----数组

目录

​编辑

数组

1. 概念:

2. 定义格式:

3. 访问元素:

4. 特点

5. 注意

6. 分类

一维数组:只有一个下标的数组

1. 格式:

2. 访问元素:

3. 数组名:数组首元素的首地址

4. 初始化:

4.1. 全部初始化:

4.2. 部分初始化

4.3. 未初始化:

5. 定义空数组:

6. 引用:

7. 内存分配

8. 数组遍历:

9. 数组大小

清零函数

1. bzero

2. memset(可扩展)

字符数组

1.概念

2.形式

3.输入输出

输入

输出

计算字符串的实际长度

sizeof和 strlen的区别

冒泡排序

选择排序:

二维数组

1.格式

2.访问元素

3.数组元素个数:

4.二维数组的大小:

5.数组名

6.初始化

1) 全部初始化:

2) 部分初始化:未初始化的部分元素值为0

3) 未初始化:随机值,需要单独的赋值

7.内存分配

内存分配

二维数组

二维数组遍历


数组

1. 概念:

具有一定顺序的若干变量的集合

2. 定义格式:

存储类型 数据类型 数组名[元素的个数];

int arr[5];

数组名:代表数组首元素的首地址,arr地址常量,不能为左值,不能被赋值

3. 访问元素:

数组名[下标]; 下标是从零开始

访问第一个元素:arr[0];

访问第n个元素:arr[n-1];

注意数组越界问题

4. 特点

1) 数据类型相同

2) 内存连续

5. 注意

1. 数组的数据类型就是数组元素的数据类型

2. 数组名要符合标识符的命名规则

3. 在同一函数中,数组名不要与变量名相同

int arr[5];

int arr; // 错误,在同一函数中,这样不被允许

4. 下标从0开始,到 n-1 结束

6. 分类

一维数组、二维数组

一维数组:只有一个下标的数组

1. 格式:

存储类型 数据类型 数组名[元素个数];

2. 访问元素:

数组名[下标]; 下标从0开始

3. 数组名:数组首元素的首地址

4. 初始化:

4.1. 全部初始化:

定义数组的同时全部初始化

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

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int arr[5] = {1, 2, 3, 4, 5};
    printf("%d\n", arr[0]);
    printf("%d\n", arr[1]);
    return 0;
}
4.2. 部分初始化

int arr[5] = {1, 2}; // 1 2 0 0 0

未初始化的元素值为0

4.3. 未初始化:

随机值,需要单个元素赋值

int arr[5]; // 随机值

进行单个元素赋值:

arr[0] = 1;

arr[1] = 2;

5. 定义空数组:

1) 可以全部初始化:

int arr[5] = {0 , 0 , 0, 0, 0};

2) 可以部分初始化:

int arr[5] = {0};

3) 这样也可以:

int arr[5] = {};

注意:函数里面开辟的数组值为随机值,全局里面开辟的数组值为零

6. 引用:

1. 先定义后引用

2. 每次只能引用一个数组元素arr[i],如果想要引用所有元素可以使用循环遍历

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

    int i;
    for (i = 0; i < 5; i++)
    {
        scanf();  /  printf();
    }

3. 引用时防止数组越界,有时编译器不会报错

4. 打印数组元素的地址用 %p 格式

printf("%p\n", arr[i]); arr[i] 是变量,不能以%p的格式打印,需要加取地址符 &

printf("%p\n", &arr[i]);

7. 内存分配

一一对应的关系

8. 数组遍历:

把数组下标作为循环变量,用 for 循环遍历

    int arr[5] = {};

    int i, j;
    for (i = 0; i < 5; i++)
    {
        scanf("%d", &arr[i]);
    }
    for (j = 0; j < 5; j++)
    {
        printf("%d\n", arr[j]);
    }

9. 数组大小

int arr[5];  // 20
double d_arr[5]; // 40
char str[32];  // 32

计算数组的大小:
1. 数据元素个数 * 数据类型的大小
2. sizeof(数组名)

计算元素个数:
1. 直接观察
2. sizeof(数组名)/sizeof(数据类型)

练习:计算斐波那契数列前15项并逆序输出

1 1 2 3 5 8 13 21 .....

int arr[15] = {1, 1};

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int arr[15] = {1, 1};

    int i, j;  // 循环变量
    for (i = 2; i < 15; i++)
    {
        arr[i] = arr[i-1] + arr[i-2];
    }
    for (j = 14; j >= 0; j--)
    {
        printf("%d\n", arr[j]);
    }
    return 0;
}

清零函数

1. bzero

#include <strings.h>

void bzero(void *s, size_t n);

功能:内存空间设置为零

参数:s:要清空的空间的首地址

n:字节大小

返回值:无

#include <stdio.h>
#include <strings.h>

int main(int argc, char const *argv[])
{
    int arr[15] = {1, 1};

    int i, j;  // 循环变量
    for (i = 2; i < 15; i++)
    {
        arr[i] = arr[i-1] + arr[i-2];
    }
    bzero(arr, sizeof(arr));
    for (i = 0; i < 15; i++)
    {
        // arr[i] = 0;
        printf("%d\n", arr[i]);
    }
    return 0;
}

2. memset(可扩展

#include <string.h>

void *memset(void *s, int c, size_t n);

功能:将内存空间设置为0

参数:s:要请空的空间的首地址

c:要设置的值,设置为0

n:字节大小

返回值:要清空的空间的首地址

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

int main(int argc, char const *argv[])
{
    int arr[15] = {1, 1};

    int i, j;  // 循环变量
    for (i = 2; i < 15; i++)
    {
        arr[i] = arr[i-1] + arr[i-2];
    }
    memset(arr, 0, sizeof(arr));
    for (i = 0; i < 15; i++)
    {
        printf("%d\n", arr[i]);
    }
    return 0;
}

字符数组

字符数组可以存放字符串

1.概念

元素的数据类型为字符型的数组

2.形式

char str[]={'a','b','c'};  //sizeof(str)==3
char str[]={"hello"};      //sizeof(str)==6
char str[]="hello";        //sizeof(str)==6
char str[32]="hello";        //sizeof(str)==32

注意:字符串赋值时常常会省略元素的个数,需要注意数组越界问题

3.输入输出

输入

char str[32] = {};

1) scanf("%c", &str[i])

scanf("%s", str);

#include <stdio.h>

int main(int argc, char const *argv[])
{
    char str[32] = {};
    // for (int i = 0; i < 5; i++)
    // {
    //     scanf("%c", &str[i]);
    // }
    scanf("%s", str);
    printf("%s\n", str);
    
    return 0;
}

输入的字符串不能含有空格,因为 scanf 输入字符串遇到空格或 \n都会认为字符串输入结束,空格后面的内容就不再存放到数组当中

如果需要输入空格可以使用下面的格式:

1)scanf(“%[^\n]”,str);

2)gets
char *gets(char *s);
// 功能:从终端获取字符串
// 参数:s:目标字符数组的首地址
// 返回值:目标字符数组的首地址
 char str[32] = {};
    gets(str);
    printf("%s\n", str);
    // 报了个警告
    // gets比较危险,不推荐使用,因为不会数组越界检查的,但是是可以使用的

输出
1.printf("%s\n", str);
2.for(int i = 0; i < 32; i++)
	{
		printf("%c", str[i]);
}
printf("\n");

3.puts
int puts(const char *s)

// 功能:向终端输出字符串
// 参数:s:要输出字符数组的首地址
// 返回值:输出字符的个数

例题:判断对错

char str[10] = {};

str[10] = "hello"; // 错误,数组越界

str = "hello"; // 错误,str是地址常量,不能为左值

strcpy(str, "hello");

练习:将一串字符串进行倒置char buf[32]=”hello”;//olleh

#include <stdio.h>

int main(int argc, char const *argv[])
{
    char buf[] = "hello ";
    // 将数组的元素个数拿掉,计算字符串的实际长度,但不符合题干
    // szieof(buf)-1; 
    
    // 中间变量
    char t;  
    // i: 循环变量
    // n: 字符串的实际长度
    int i, n = sizeof(buf)-1;
    
    // 通过循环的方式计算字符串的实际长度
    // for (n = 0; buf[n] != '\0'; n++);  
    
    // 交换
    for (i = 0; i < n/2; i++)
    {
        
        t = buf[i];
        buf[i] = buf[n-1-i];
        buf[n-1-i] = t;
    }
    printf("%s\n", buf);

    
    return 0;
}

计算字符串的实际长度

  1. for循环遍历数组,直到\0为止

for(n = 0; buf[n] != '\0', n++);

  1. strlen

#include <string.h>

size_t strlen(const char *s);

功能:计算字符串的实际长度(不包括\0)

参数:s:要计算的字符串的首地址

返回值:字符串的实际长度

char buf[32]="hello";
int num =strlen(buf);
printf("%d\n", num);// 5
sizeof(buf);// 32

char str[] = "hello"
    int num = strlen(buf);
    printf("%d\n", num); // num = 5
    sizeof(str); // 6
sizeof和 strlen的区别
  1. sizeof是关键字,strlen是函数
  2. sizeof是计算数据所占空间大小,strlen是计算字符串的实际长度
  3. sizeof计算包括\0,strlen计算不包括\0,计算字符串长度时(元素个数省略情况下),sizeof比strlen大1

练习:实现字符串大小转换

冒泡排序

两两比较,第i个和 i+1个比较

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

第一轮:

45321

43521

43251

43215

第二轮:

34215

32415

32145

第三轮:

23145

21345

第四轮:

12345

n个数:比较n-1轮,每轮的交换次数从 n-1开始依次递减

算法实现:

#include <stdio.h>
#define N 10

int main(int argc, char const *argv[])
{
    int arr[N];
    for (int i = 0; i < N; i++)
    {
        scanf("%d", arr[i]);
    }

    for (int i = 0; i < N - 1; i++) // 轮数
    {
        for (int j = 0; j < N - 1 - i; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }

    for (int i = 0; i < 5; i++)
    {
        printf("%d", arr[i]);
    }
    printf("\n");

练习:将10个数进行降序排序

选择排序:

n个数:先找出最小值的下标暂存,选择出最小值与第一个数进行交换

排序过程:

1) 首先通过 n-1 次比较,从 n 个数中找出最小的,将它与第一个数交换 第一趟选择排序,结果最小的数被安置在第一个元素位置上

2) 再次通过 n-2 次比较,从剩余的n-1个数中下标对应的最小的值,将它与第二个数交换 第二趟选择排序

3) 重复上述过程,共经过 n-1 趟排序后,排序结束

算法实现:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int arr[5] = {5, 4, 3, 2, 1}, n = 5;
    for (int i = 0; i < n-1; i++)
    {
        // 把第一个值当作最小值,进行比较,后面直接拿k去进行比较
        int k = i;
        for (int j = 0; j < n; j++)
        {
            if(arr[j] < arr[k])
            {
                k = j;
            }
        }
        if(i != k)
        {
            // 交换
            arr[k] 和 arr[i] 交换;
        }
    }
    return 0;
}

二维数组

1.格式

存储类型 数据类型 数组名[行数][列数]

int arr[2][3];

2.访问元素

数组名[行下标][列下标];(下标从0开始)

arr[0][0]:第一行第一列的元素

arr[1][2]:第二行第二列的元素

行下标、列下标都不能越界

行数可以省略,但是列数不能省略

int arr[][3];

3.数组元素个数:

行数*列数

sizeof(数组名) / sizeof(数据类型)

4.二维数组的大小:

sizeof(数组名)

数据类型大小 * 元素个数

5.数组名

arr:第一行的首地址

arr+1:第二行的首地址

6.初始化

1) 全部初始化:

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

printf("%d %d %d\n", arr[0][0], arr[0][1], arr[0][2]);// 1 2 3

printf("%d %d %d\n", arr[1][0], arr[1][1], arr[1][2]);// 4 5 6

2) 部分初始化:未初始化的部分元素值为0

int arr[2][3] = {1, 2, 3, 4}; //顺序赋值

printf("%d %d %d\n", arr[0][0], arr[0][1], arr[0][2]); // 1 2 3

printf("%d %d %d\n", arr[1][0], arr[1][1], arr[1][2]); // 4 0 0

intarr[2][3] = {{1, 2}, {4, 5}};// 按行赋值1 2 0 4 5 0

3) 未初始化:随机值,需要单独的赋值

int arr[2][3];

A

C

7.内存分配

内存分配

// a 和 a[0] 并不完全相同,级别不同,后面会讲,数值上是一样的,级别不一样
// a 是行地址
// a[0] 是列地址
//[]降级
// a 表示 第一行的首地址
// a+1 表示 第二行的首地址
// a[0] 表示第一行第一列的地址
// a[1] 表示第二行第一列的地址

二维数组

二维数组遍历

for循环嵌套,外层行数,内层是列数

int arr[m][n] = {};

for(i = 0; i < m; i++)
{
    for(j = 0; j < n; j++)
    {
        // 可以输入也可以输出
        scanf() / printf()
    }
}

例:
    int arr[2][3] ={};

    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            scanf("%d", &arr[i][j]);
        }
    }
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("%d", arr[i][j]);
        }
    }

;