数组(补充)

数组(Array)

1、数组的定义

1.1 何为数组

        数组是相同类型数据的有序集合。数据描述的是相同类型得到数据按照一定先后次序排列组合而成。每一个数据成为一个元素,每个元素可以通过下标的方式访问它们。数组的定义的一般方式为:“数组类型 数组名[常量表达式]”,需要注意的是,常量表达式用来表示数组长度,它的下标是从0开始的。而数组名表示数组首地址,是地址常量,数组再被编译时分配连续内存,它的大小是这样计算的: 内存字节数=数组长度*sizeof(数据类型)

1.2 数组的特点

1、长度是确定的。数组一旦被创建,它的大小就是不可以改变的。

2、其元素类型必须是相同类型,不允许出现混合类型。

3、数组可以存储任何存储类型,包括基本类型和引用类型。

4、数组变量属于引用类型,数组也是对象。

5、数组必须先定义,后使用。

6、只能逐个引用数组,不能一次引用整个数组。

2、数组的初始化

2.1  一维数组的创建

数组的创建方式:

type_t   arr_name   [const_n];
//type_t 是指数组的元素类型
//arr_name 是数组的名字
//const_n 是一个常量表达式,用来指定数组的大小

数组创建的实例:

//代码1
int arr1[10];
char arr2[10];
float arr3[1];
double arr4[20];
//代码2
//用宏定义的方式
#define X 3
int arr5[X];
//代码3
//错误使用
//数组创建,[]要给一个常量才可以,不能使用变量。可以使用常量,或者直接使用宏定义
int count = 10;
int arr6[count];
2.1 一维数组的初始化

数组的初始化是指,在创建数组的同时同时给数组的内容一些合理初值。

1、数组个数和数值个数一致

int arr1[5] = {5, 8, 6, 9, 3};

2、数组大小大于初始元素数目,超过初始元素部分自动补0

int arr2[6] = {5, 6, 7};

3、不指定数组大小

int arr3[] = {5, 6, 4, 3};

5、存储字符串时,注意数组大小和最后一项的差别

(1)字符数组存储字符串

char arr4[] = "abcdef";//当不指定数组大小时,最后一位默认补0

(2)字符数组的大小和字符串字符个数一致

char arr5[6] = "abcdef";

注:这样初始化时存在问题,因为无法正常读取字符串结束标志('\0'),导致字符串的长度和内容不能得知。

(3)字符数组的大小大于字符串的字符数

char arr6[6] = "zxc"; //不足数组长度部分自动补0

说明:

1、数组是具有相同元素的集合,数组的大小由元素的个数乘以元素的大小

2、数组只能够整体初始化,不能被整体赋值,只能使用循环从第一个元素逐个遍历赋值。

3、初始化时,数组的维度或者元素个数可以忽略,编译器会根据花括号中元素的个数初始化数组元素的个数。

4、当花括号中用于初始化值的个数不足数组元素的大小时,数组剩下的元素依次用0进行初始化。

5、字符串数组在计算机内部用的是对应的ASCII码值进行存储的。

6、一般“”内的字符串,不用数组保存时,一般直接编译到字符变量区,并且不可被修改。

在内存中存储

2.3 一维数组的使用

下标引用操作符[],它其实就是数组访问的操作符,e.g.

#include <stdio.h>
int main() {
    int arr[10] = {0}; //数组的不完全初始化
    int sz = sizeof(arr) / sizeof[0]; //计算数组中元素的个数
    //下面对数组元素进行赋值,数组元素是使用下标来访问的,下标从0开始
    int i = 0; //做下标此时可以是变量
    for (i = 0; i<10; i++) {
        arr[i] = i;
    }
    //输出数组的内容
    for (i = 0; i<10; i++) {
        printf("%d", arr[i]);
    }
    renturn 0;
}

说明:

1、sizeof()操作符用于取长度,以字节为单位。sizeof(数组名)即求的整个数组的大小。sizeof(首元素)即求整个元素的大小。用0下标,因为数组至少存在一个元素,所以0下标一定存在。

2、数组是使用下标访问的,数组下标从0开始。

3、数组大小可以通过计算得到,一般计算方式为 sizeof(arr)/sizeof[0]

2.4一维数组在内存中的存储
#include <stdio.h>
int main() {
    int arr[0] = {10};
    int size = sizeof(arr) / sizeof(arr[0]);
    for (i = 0; i<size; i++) {
        printf("&arr[%d] = %p\n", i, &arr[i]);
    }
    return 0;
}

 说明:

1、随着下标的增长,元素的地址也在有规律的增长,进而可以推算出数组中的元素在内存中是连续存储的。

2、在C语言中,任何变量(基本变量、指针变量、结构体变量和数组变量)的空间都是整体开辟的,但任何变量的起始地址一定是开辟字节中最小的。

3、二维数组及多维数组

3.1二维数组的创建和初始化

(1)二维数组的创建

//数组创建
int arr[3][4];
char [][5];
double arr[2][4];

二维数组创建时,行数可以不写,并且所有维度的第一个方括号的内容可以忽略。

(2)二维数组的初始化

//数组初始化
int arr[3][4] = {1, 2, 3, 4};
int arr[3][4] = {{1,2},{4,5}};
int arr[][4] = {{2,3},{4,5}};

说明:花括号中的一个花括号代表一维数组的初始化,当里面无花括号分组时,按照元素的顺序逐个进行初始化,预先未赋值的位置用0初始化。

3.2二维数组的使用

        二维数组的使用也是通过下标的方式,用双重循环嵌套来使用。

include <stdio.h>
int main() {
    int arr[3][4] = {0};
    for (int i = 0; i<3; i++) {
        for (int j = 0; j<=4; j++) {
            a[i][j] = 4*i + j;
        }
    }
     for (int i = 0; i<3; i++) {
        for (int j = 0; j<=4; j++) {
            printf("%d", a[i][j]);
        }
    }
    return 0;
}

        如果尝试打印一下上述代码中的二维数组的每个元素。

include <stdio.h>
int main() {
    int arr[3][4] = {0};
    for (int i = 0; i<3; i++) {
        for (int j = 0; j<=4; j++) {
            printf("arr[%d][%d] = %p\n", i, j, &a[i][j]);
        }
    }
    return 0;
}

说明:二维数组在内存上也是线性连续存储的。

4、数组作为函数参数传递

1、调用函数传输函数组时,应注意减少函数传输数组时的成本问题。因为传参时,需要临时拷贝,如果数组过大会浪费资源,严重的话可能会导致栈溢出。

2、数组元素降维成指向数组内部元素的指针。

3、对指针加一,等于指针所指向的类型的大小。

4.1 一维数组
#include <stdio.h>

void base(int arr[]) {
    printf("a = %d\n", sizeof(arr));//数组降维成指针后的指针大小,在32位系统下指针为4字节
    printf("b = %d\n", sizeof(arr[0]));//数组首元素的大小
    printf("sz = a/b = %d\n", sizeof(arr) / sizeof(arr[1])); //大小为1
    printf("arr = %p\n", arr); //数组首元素地址
    printf("&arr = %p\n", &arr); //指针的地址
    printf("arr + 1 = %p\n", arr + 1); //下一个元素的地址
    printf("&arr + 1 = %p\n", &arr + 1); //指针下一项的地址
}

int main(void) {
    int shuzu[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    printf("a = %d\n", sizeof(shuzu)); //数组总大小
    printf("b = %d\n", sizeof(shuzu[0]));//数组首元素的大小
    printf("sz = a/b = %d\n", sizeof(shuzu) / sizeof(shuzu[0])); //数组元素个数
    printf("shuzu = %p\n", shuzu); //数组首元素地址
    printf("&shuzu = %p\n", &shuzu); //代表整个数组,但是地址仍是首元素地址
    printf("shuzu + 1 = %p\n", shuzu + 1); //下一个元素的地址
    printf("&shuzu + 1 = %p\n", &shuzu + 1); //跳过整个数组后紧挨着的地址,此时改地址减去
    //首元素地址等于数组大小
    printf("\n\n");
    base(shuzu);
    
    return 0;      
}

说明:

1、sizeof(数组名),计算整个数组的大小,sizeof()内部单独存放一个数组,数组名表示整个数组。

2、&数组名,取出的是数组的地址。&数组名,数组名表示整个数组。

3、形参格式,例如int arr[]或者int *arr,两者等价

4、形参个数可以被忽略,否则有可能改变实参的大小,最好是忽略,亦或是填写比实参元素个数大的值。

5、用sizeof()求数组元素个数时,尽量在数组定义是求,否则传参后数组会降维成指针。

4.2 二维数组

        数组元素降维会变成指向内部元素类型的指针,二维int整型数组内部的元素不再是int类型,而是具有四个整型的一维数组。对指针加一,就是加上指针所指向的类型的大小。对二维数组指针加一,加上的值为内部一维数组的大小。

#include <stdio.h>

void base(int arr[][4]) {
    printf("a = %d\n", sizeof(arr));//数组降维成指针后的指针大小,在32位系统下指针为4字节
    printf("b = %d\n", sizeof(arr[0][0]));//数组首元素的大小
    printf("sz = a/b = %d\n", sizeof(arr) / sizeof(arr[0][0])); //大小为1
    printf("arr = %p\n", arr); //数组首元素地址
    printf("&arr = %p\n", &arr); //指针的地址
    printf("arr + 1 = %p\n", arr + 1); //下一个元素的地址
    printf("&arr + 1 = %p\n", &arr + 1); //指针下一项的地址
}

int main(void) {
    int shuzu[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    printf("a = %d\n", sizeof(shuzu)); //数组总大小
    printf("b = %d\n", sizeof(shuzu[0][0]));//数组首元素的大小
    printf("sz = a/b = %d\n", sizeof(shuzu) / sizeof(shuzu[0][0])); //数组元素个数
    printf("shuzu = %p\n", shuzu); //数组首元素地址
    printf("&shuzu = %p\n", &shuzu); //代表整个数组,但是地址仍是首元素地址
    printf("shuzu + 1 = %p\n", shuzu+1); //下一个元素的地址,这是其内部数组的一维数组    
    printf("&shuzu + 1 = %p\n", &shuzu); //跳过整个数组后紧挨着的地址,此时改地址减去
    //首元素地址等于数组大小
    printf("\n\n");
    base(shuzu);
    
    return 0;      
}

说明:1、形参格式 int arr[][4] 或者 int (*arr)[4],这里为指向具有四个整型元素的一维数组的数组指针。除了第一个中括号的内容可以省略,后面中括号的内容不能省略,因为下标是数组类型的一部分,省略后会导致数组类型不明确。

2、其实所有数组,本质上都是一维数组,只不过内部元素不一样。例如:三维数组内部为二维数组,二维数组内部为一维数组。

5、数组指针和指针数组

数组指针:是指针,指向数组。e.g.  int (*arr)[10]

指针数组:是数组,数组内容存放的是指针。e.g. int *arr[10]

        其中,不同运算符之间有一个运算顺序:()>[]>*

        所以,对于 (*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一维数组,数组长度为n,这是“数组的指针”,即数组指针,*p[n]:根据优先级,先看[],则p是一个数组,再结合*,这个数组的类型是指针类型,共n个元素,这是“指针的数组”,即数组指针。

5.1指针数组
#include <stdio.h>

int main(){
    int *p[4];
    int arr1[3] = {1, 2, 3};
    int arr2[4] = {2, 4, 6, 8};
    int arr3[5] = {0};
    int arr4[2] = {2, 2};
    p[0] = arr1;
    p[1] = arr2;
    p[2] = arr3;
    p[3] = arr4;
    printf("%d\n", *(p[0] + 1));
    printf("%d\n", *(p[1] + 1));
    printf("%d\n", *(p[2] + 1));
    printf("%d\n", *(p[3] + 1));
    
    return 0;
 
}

对于语句int*p[4],因为[]的优先级要比*要高,所以p先于[]结合,构成一个数组的定义,数组名为p,而int*修饰的数组的内容,即数组的每个元素。也就是说,该数组包含4个指向int类型的指针,如图所示,因此它是一个指针数组。

5.2数组指针
#include <stdio.h>

int main(void) {
    int shuzu[3][4] = { 0,1,2,3,4,5,6,7,8,9,0,0};
    int(*arr)[4] = shuzu;
    for (int i = 0; i<3;i++) {
        for (int j = 0; j<4; j++) {
            printf("arr[%d][%d] = %d",i, j,arr[i][j]);
        }
        printf("\n");
    }
    return 0;
}
    

      其次,对于语句int(*arr)[4],“()”的优先级比[]高,*和arr构成一个指针的定义,指针变量名为arr,而int修饰的是数组的内容,即数组中的每个元素。也就是说,arr是一个指针。它指向一个包含4个int类型数据的指针,如图,很显然,它是一个数组指针。 

6、程序举例

 例1: 读10个整数存入数组,找出其中最大值和最小值

/*例1*/
#include <stdio.h>
#define SIZE 10
int main {
    int x[SIZE], i, max, min;
    printf("Enter 10 intrgers: \n");
    for (i = 0; i<SIZE; ++i) {
        printf("%d", i+1);
        scanf("%d", &i);
    }
    max = min = x[0];
    for (i=1; i<SIZE; i++) {
        if (max < x[i]) max = x[i];
        if (min > x[i]) min = x[i];
    }
    printf("Maxinum value in %d\n",max);
    printf("Minimum value in %d\n",min);
}

 例2 对10个元素实现冒泡排序(升序)   

/*例2*/
#include <stdio.h>
int main() {
    int a[11], i, j, t;
    for (i = 1; i<11; i++) {
        scanf("&d", &a[i]);
    }
    printf("\n");
    for (j = 1; j<=9; j++) {
        for (i = 1; i<=10-j; i++) {
            if (a[i]<a[i+1]) {
                t=a[i+1];
                a[i+1]=a[i];
                a[i]=t;
            }
        }
    }
    printf("The sorted numbers:\n");
    for (i = 1; i<11; i++) {
        printf("%d\n", a[i]);
    }
}

例3:用简单选择法对10个数进行排序 (升序)

/*例3*/
#include <stdio.h>
int main() {
    int a[11], i, j, t,k;
    for (i = 1; i<11; i++) {
        scanf("&d", &a[i]);
    }
    printf("\n");
    for (j = 1; j<=9; j++) {
        k = i;
        for (i = ; i<=10-j; i++) {
            if (a[j] < a[k]) k = j;
        }    
        if (i!=k) {
            t=a[i+1];
            a[i+1]=a[i];
            a[i]=t;
        }
    }
    printf("The sorted numbers:\n");
    for (i = 1; i<11; i++) {
        printf("%d\n", a[i]);
    }
}

7、参考文献

王道2025数据结构考研复习指导

c语言—数组详解(建议收藏)_c语言数组-优快云博客

C语言总结(一维数组、二维数组、字符数组和字符串)_一维数组二维数组以及字符数组-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值