C基础:数组

目录

1.数组的基本用法

1.1 概念

1.2 定义格式

1.3 访问元素

2.一维数组

2.1 一维数组的概念

2.2 初始化

2.3 定义空数组

2.4 数组引用

2.5 数组的大小

2.6 清零函数

2.6.1 bzero() 函数

2.7.2 memset()函数

2.7 数组的内存分配

3.字符数组

3.1 表示形式

3.2 输入和输出

3.2.1 输入

3.2.2 输出

3.3. 计算字符串长度

3.3.1 用循环统计

3.3.2 用strlen()

3.3.3 sizeof和strlen的区别


1.数组的基本用法

1.1 概念

数组(Array)是有序元素序列

若将有限个类型相同的变量的集合命名,那么这个名称为数组名。

重点必须是类型相同和连续的变量集合

1.2 定义格式

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

例如:(auto) int a[5];

数组名:代表数组的首地址,也就是第一个元素的地址。a是地址常量,不能为左值,不能被赋值。

数组定义方法:

(1)数组名定义规则跟变量名相同,遵循标识符定义规则

(2)数组名后使用方括号括起来的常量表达式表示元素个数。

(3)常量表达式中可以包含常量和符号常量(宏定义),不能包含变量

1.3 访问元素

数组名[下标];

注意:数组元素下标从0开始

例如:

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

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

注意数组越界问题:

特点:

数据元素的数据类型相同

内存连续

注意:

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

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

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

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

2.一维数组

2.1 一维数组的概念

只有一个下标的数组。

定义格式:存储类型 数据类型 数组名[元素个数];

访问元素:数组名[下标], 下标从0开始。

数组名:数组首地址,也就是第一个元素的地址。

2.2 初始化

(1)定义时全部初始化
int a[5] = {1, 2, 3, 4, 5};
    printf("%d\n", a[0]);
    printf("%d\n", a[1]);
    printf("%d\n", a[2]);
    printf("%d\n", a[3]);
    printf("%d\n", a[4]);

(2)定义时部分初始化,未初始化的元素值自动为0

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

    printf("%d\n", a[0]); //1
    printf("%d\n", a[1]); //2
    printf("%d\n", a[2]); //0
    printf("%d\n", a[3]); //0
    printf("%d\n", a[4]); //0
(3)未初始化:只定义不赋值,需要单个元素赋值。(不然局部变量为随机值)
 int a[5];
    a[0] = 1;
    a[1] = 2;
    a[2] = 3;
    a[3] = 4;
    a[4] = 5;

    for(int i=0; i<5;i++)  //i的值循环为: 0 1 2 3 4 5(到5不满足循环条件出循环)
        printf("%d\n",a[i]);  //循环打印:a[0] a[1] a[2] a[3] a[4] a[5]

注意数组越界问题:

int a[3] = {4,3,2,1}; //错误,数组越界

a[3] =10; //错误,数组越界了

2.3 定义空数组

(1)int a[5] = {0,0,0,0,0};

(2)int a[5] = {0};

(3)int a[5] = {};

2.4 数组引用

(1)先定义后引用

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

(3)打印数组元素地址用%p格式

2.5 数组的大小

int a[5]; //4*5 = 20
double b[3]; //8*3 = 24
char c[32];  //32

计算方式:

(1)手算:数元素个数*数据类型大小

(2)用sizeof: sizeof(数组名);

数组元素的个数 = sizeof(数组名) / 元素大小;

2.6 清零函数

2.6.1 bzero() 函数

#include <strings.h>

void bzero(void *s, size_t n);

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

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

n: 字节大小

返回值:无

2.7.2 memset()函数

#include <string.h>

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

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

参数:s:指定内存首地址

c:要设置的数,一般为0

n:要设置的内存大小

返回值:无

2.7 数组的内存分配

int a[5];

a是数组名,也是数组的首地址也就是第一个元素的地址,即&a[0]。

a+1 是数组第二个元素的地址,即&a[1]。

数组再内存中分配如下图:

3.字符数组

因为C语言没有字符串类型,所以可以用字符数组的形式表示字符串。

概念:类型为字符的数组,也就是数组中每个元素是字符型。可以组成字符串。

3.1 表示形式

(1)单个字符表示:

char s[5] = { 'h', 'e', 'l', 'l', 'o'}; //sizeof(5) = 5;

char s1[] = { 'h', 'e', 'l', 'l', 'o'}; //sizeof(s1) = 5; //定义数组的同时初始化可以省略元素个数,元素个数取决于你赋值的元素个数。

(2)用字符串表示,结尾会自动添加上'\0'

char s2[] = "hello"; //sizeof(s2) = 6

char s3[] = {"hello"}; //sizeof(s3) = 6

char s4[6] ={"hello"}; //sizeof(s4) = 6

char s5[6] ="hello"; //sizeof(s5) = 6 //常用

char s6[] ={}; //错误,如果定义时不赋值则不能省略元素个数

初始化和其他类型数组相同

3.2 输入和输出

3.2.1 输入

(1)scanf:

char s[32] = {};
    scanf("%s", s);

    printf("%s\n", s);

不能输入空格,如果有空格,空格后面的内容不会存入数组。

例如:以下程序输入hello world只能存入hello

如果需要输入空格则:

har s[32] = {};
    scanf("%[^\n]", s);  //除了\n以外所有字符都可以输入到s地址下空间内保存,遇到\n就结束

    printf("%s\n", s);

输入字符串会在后面加上'\0'

(2)用for遍历输入

char s[6] = "";
    for (int i = 0; i < 6; i++)
        scanf("%c", &s[i]);

(3)gets()

#include <stdio.h>

char *gets(char *s);

功能:从终端获取字符串输入

参数:s:目标字符串首地址

返回值:目标字符串首地址

注意:没有数组越界检查,使用时会报警告。

3.2.2 输出

(1)用printf()
char s[32]="hello"
printf("%s\n",s);

(2)for循环

char s[32] = "hello";

for (int i = 0; i < 32; i++)

printf("%c", s[i]);

(3)puts()函数

int puts(const char *s)

功能:向终端打印字符串

参数:打印的字符串首地址

返回值:字符串长度

char s[32] = "";
    gets(s); //在结尾加个\0,不会接收到回车
    puts(s); //在结尾自动加个回车

3.3. 计算字符串长度

char s[32]="hello"; //sizeof(s)=23

3.3.1 用循环统计

 char s[32] = "hello";
    int i;
    // int len = 0;
    // for (i = 0; s[i] != '\0'; i++)
    //     len++;
    // printf("%d\n", len);  //5
    i = 0;
    while (s[i] != '\0')
    {
        i++;
    }
    printf("%d\n", i); //5

3.3.2 用strlen()

#include <string.h>

size_t strlen(const char *s);

功能:计算字符串长度

参数:字符串的首地址

返回值:返回字符串实际长度,不包括'\0'在内。

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

3.3.3 sizeof和strlen的区别

(1) sizeof是关键字,strlen是函数。

(2)sizeof是计算数据所占空间大小,strlen计算字符串的实际长度。

(3)sizeof计算包括\0,strlen计算不包括\0;计算字符串长度时(元素个数省略情况下),sizeof比strlen大1。

4.排序

4.1 冒泡排序

4.1.1 排序过程

(1)比较第一个数与第二个数,若为逆序a[0]>a[1],则交换;然后比较第二个数与第三个数;依次类推,直至第n-1个数和第n个数比较为止,第一趟冒泡排序,结果最大的数被安置在最后一个元素位置上

(2)对前n-1个数进行第二趟冒泡排序,结果使次大的数被安置在第n-1个元素位置

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

4.1.2 原理

第一遍每一个数都会被比较到,总会排到最大的数,那么最大的数肯定会排到最后面,因为只要比前面数大就会排到后面。后面排序同理。

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

例如:int a[5]={5,4,3,2,1};

第一轮

第二轮

第三轮

第四轮

45321

34215

23145

12345

43521

32415

21345

43251

32145

43215

i=0: 第一轮5-1=4排序

i=1: 第二轮:5-2=3排序

i=2: 第三轮:5-3=2排序

i=3: 第四轮5-4=1排序

外层轮数 = 个数 - 1 = N - 1 (i=0;i<N-1;i++)

每轮排序次数= 个数-轮数 (=N-i-1)

int a[5]={5,4,3,2,1};
for(i) //外层循环轮数
{
    for(j) //内层循环比较的次数
    {
        if(a[j]>a[j+1])
        {
            //交换
        }
    }
}

4.1.3 编程实现

#define N 5
int a[N] = {5, 4, 3, 2, 1};
int main()
{
    int t = 0, i, j;
    for (i = 0; i < N - 1; i++)    //i<4  i=4
    {
        for (j = 0; j < N - i - 1; j++)   //j<1  j=1
        {
            if (a[j] > a[j + 1])   //1 2 3 4 5
            {
                t = a[j];
                a[j] = a[j + 1];
                a[j + 1] = t;
            }
        }
    }

    for (i = 0; i < N; i++)
        printf("%d ", a[i]);
    printf("\n");
}

或者

#include <stdio.h>
#define N 5
int a[N] = {5, 4, 3, 2, 1};
int main()
{
    int t = 0, i, j;
    for (i = 1; i < N ; i++)    //i<4  i=4
    {
        for (j = 0; j < N - i; j++)   //j<1  j=1
        {
            if (a[j] > a[j + 1])   //1 2 3 4 5
            {
                t = a[j];
                a[j] = a[j + 1];
                a[j + 1] = t;
            }
        }
    }

    for (i = 0; i < N; i++)
        printf("%d ", a[i]);
    printf("\n");
}

4.2 选择排序

4.2.1 排序过程

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

(2)再通过n-2次比较,从剩余的n-1个数中找出关键字次小的记录,将它与第二个数交换—第二趟选择排序

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

4.2.2 原理

第一次排序存取最小值,然后与第一个元素做交换,以此类推。

轮数i:个数-1 = N-1 (同冒泡排序)

每轮比较次数:从a[i]和它后一个a[i+1]开始比较,一直到最后一个a[N-1]

(只要更小记录其下标)

4.2.3 编程实现

#include <stdio.h>
#define N 6
int a[N] = {100, 34, 56, 78, 99, 2};  //2 34 56 78 99 100
int main()
{
    int i, j, t;
    int min;
    for (i = 0; i < N - 1; i++)  //循环轮数  i=2
    {
        min = i;   //min=1
        for (j = i + 1; j < N; j++)  //通过每轮比较的次数把最小下标找出来保存到min里面
        {
            if (a[min] > a[j])
                min = j;      // 记录最小元素的下标
        }

        if (a[min] != a[i])  //通过把最小数排到前面
        {
            t = a[min];
            a[min] = a[i];
            a[i] = t;
        }
    }

    for (i = 0; i < N; i++)
        printf("%d ", a[i]);
    printf("\n");
}

或者

#include <stdio.h>
#define N 6
int a[N] = {100, 34, 4, 78, 99, 2}; 
int main()
{
    int i, j, t;

    for (i = 0; i < N - 1; i++)
    {
        for (j = i + 1; j < N; j++) 
        {
            if (a[i] > a[j])  //只要遇到更小元素就交换,排完这轮之后找到的最小数排到了前面
            {
                t = a[j];
                a[j] = a[i];
                a[i] = t;
            }
        }
    }

    for (i = 0; i < N; i++)
        printf("%d ", a[i]);
    printf("\n");
}
  1. 二维数组

下标两个数组下标分别下标列下标

5.1 格式

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

int a[2][3];

5.2 访问元素

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

a[0][0] : 第一行第一列元素

a[i-1][j-1]: 最后一行最后一列元素

注意

  1. 行下列下标不能越界
  2. 行数可以省略列数不能省略
  3. 数组名代表第一行地址

5.3 二维数组数组名

二维数组数组名代表第一行地址

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

a: 行的地址

a+1: 第二行地址

5.4 数组元素个数二维数组大小

元素个数行数*列数

二维数组大小

  1. 数据类型大小*行数*列数
  2. sizeof(数组名);

5.5 初始化

  1. 定义时全部初始化

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

int a1[2][3] = {{1,2,3},{4,5,6}}; //赋值

  1. 定义时部分初始化, 未初始化元素值为0

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

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

  1. 未初始化

随机值需要单独赋值 a[i][j]=

5.6 遍历二维数组

循环嵌套外层循环行数内存循环列数

int a[M][N]={};
for(i=0;i<M;i++)   //行下标循环
{
    for(j=0;j<N;j++) //列下标
    {
        scanf/prinf
    }
}

5.7 内存分配

  1. 行地址

1、二维数组中,数组名a本质是第一行地址,其数值还是数组a首元素a[0][0]的地址,即&a[0][0],第一行第一个元素的地址;

2、二维数组中,数组名a+1本质是第二行地址,其数值还是数组a的元素a[1][0]的地址,即&a[1][0],第二行第一个元素的地址;

也可以在行地址前面加*表示将行地址降级成为列地址

  1. 列地址

1、二维数组中,a[0]的值,即该数组的首元素a[0][0]的地址,即&a[0][0];

2、二维数组中,a[0]+1的值,是数组元素a[0][1]的值,即&a[0][1];

  1. 总结:二维数组i行j列表示元素和地址的方式

地址:

&a[i][j]

a[i]+1

*(a+i)+j

内容:

a[i][j]

*(a[i]+j)

*(*(a+i)+j)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值