C语言:数组(详解)

文章目录

  • 前言
  • 了解数组
    • 数组名
    • 下标引用
  • 数组的使用
    • 数组的创建
    • 数组的初始化
  • 数组在内存中的存储
    • 二维数组
    • 存储顺序
    • 二维数组的初始化
    • 下标引用
    • 数组名
  • 数组越界
  • 数组作为函数参数
  • 结尾

前言

数组(Array)是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。这些有序排列的同类数据元素的集合称为数组。

所以,数组是用于储存多个相同类型数据的集合

了解数组

数组名

int a;
int b[10];

我们可以确定a就是一个整型变量,那么b[10]就是一个整型类型的数组,b就是表示数组名,那么数组名的类型又是什么?在C语言中,数组名b实际上就是一个指针常量,即数组第一个元素的地址,类型取决于数组元素的类型;当然,在这里,不能把数组看作是指针,数组具有一些与指针完全不同的特征,数组在内存中是连续存放的,而指针只是一个标量。所以数组名表示的就是数组首元素的地址,但是,有两种情况是例外的:sizeof(数组名)和取地址&数组名,这里sizeof(数组名)表示整个数组的字节长度,而不是指针的字节长度;

int b[10];
printf(“%d”,sizeof(b));
结果:40
解释:整型数组中,一个元素表示4个字节,一个数组就是4*10=40个字节

int b[10];
printf(“%p\n”,b);
printf(“%p\n”,&b);
printf(“%p\n”,b+1);
printf(“%p\n”,&b+1);
结果:
000000000061FDF0
000000000061FDF0
000000000061FDF4
000000000061FE18

C语言:数组(详解)_第1张图片

下标引用

在数组中,我们可以通过引用数组元素下标来找到指定元素。C语言规定:数组下标从0开始。
C语言:数组(详解)_第2张图片
例如,我们想找到第五个元素,那么我们就直接引用b[4]即可。实际上,在C语言中,b[4]是用解引用来调取的,即*(b+4),C语言用[]来表示,使表达上更加简洁了。
来看下面代码:

#include 
int main()
{
 int arr[10] = {0};//数组的不完全初始化
    //计算数组的元素个数
    int sz = sizeof(arr)/sizeof(arr[0]);
 //对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
 int i = 0;//做下标
 for(i=0; i<10; i++)
 {
 arr[i] = i;
 } 
 //输出数组的内容
 for(i=0; i<10; ++i)
 {
 printf("%d ", arr[i]);
 }
 return 0;
}

在这里插入图片描述
这就是对数组的下面引用,我们可以通过for循环来进行进行遍历数组,可以进行赋值,打印等一系列操作。

数组的使用

数组的创建

简单的来说,创建一个数组就是数组名加上[],花括号需要给出常量值。如:
int arr1[10];
接着我们看,

int count = 10;
int arr2[count];

这里可不可行呢?

数组创建,在C99标准之前, [] 中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化。

数组的初始化

数组的初始化和变量的初始化意义是相同的,都是为了给出合理的初始值。
如:

int arr1[10] = {1,2,3};
int arr2[] = {1,2,3,4};
int arr3[5] = {12345}char arr4[3] = {'a',98, 'c'};
char arr5[] = {'a','b','c'};
char arr6[] = "abcdef";

arr1中已经确定了该数组有10个元素,我们可以用{}来对数组进行赋值,但是我们可以看到这里只是赋值了3个,C中规定,未被赋值的默认为0.所以前三个元素分别被赋值为1,2,3,其他为0.
arr2中,[]没有给出指定个数,但是在后面的花括号初始化中,赋值了4个元素,所以,就被默认为arr2中有4个元素,且4个元素分别被赋值。
arr3中就是对第一个元素到最后一个元素都赋值了。
arr4是一个字符数组,我们发现第二个元素赋值成98,那么对于字符来说,这个98代表的是ASCLL表中第98个值,为‘b’。
arr5等同于arr4
arr6我们发现是用一串字符串来初始化,对于字符数组来说,这是合理的。因为一个元素表示一个字符。所以,对于下面两个数组,其实是等价的。

char arr1[] = "abc";
char arr2[3] = {'a','b','c'};

数组在内存中的存储

上面我们说过,数组在内存中是连续存储的,我们来看以下代码:

#include 
int main()
{
 int arr[10] = {0};
 int i = 0;
    int sz = sizeof(arr)/sizeof(arr[0]);
    
 for(i=0; i<sz; ++i)
 {
 printf("&arr[%d] = %p\n", i, &arr[i]);
 }
 return 0;
}

C语言:数组(详解)_第3张图片
数组地址是从低地址到高地址的且相邻地址相差4,正好是一个整型字节。所以得出数组在内存中是连续存放的
C语言:数组(详解)_第4张图片

二维数组

如果说一维数组是一条线的话,那么二维数组就是一个面。
二维数组的表示:

int arr[3][4];
char arr[3][5];
double arr[2][4];

我们以其中的整型二维数组来说明,arr是一个包含3个元素的向量,每个元素本身还是一个包含5个元素的向量。换句话说,arr是个一维数组的一维数组。也就是说,我们可以把第一个[]中常量看作行数,第二个[]中常量看作是列数来进行表示。
C语言:数组(详解)_第5张图片
但要记住,这只是为了方便理解给用户自己看的,是一种伪装形式,在多维数组也是如此。

存储顺序

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

结果:
C语言:数组(详解)_第6张图片
可以看出,在二维数组中,数组元素内存依旧是连续存放的。
C语言:数组(详解)_第7张图片

二维数组的初始化

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

解释:arr数组中有三行四列,初始化中,只对第一行进行了赋值初始化,其他默认为0.
C语言:数组(详解)_第8张图片

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

解释:arr中有多个花括号,在第二层花括号中,表示对该行数的某个元素进行初始化。
C语言:数组(详解)_第9张图片

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

解释:二维数组如果有初始化,行可以省略,列不能省略。

下标引用

二维数组下标引用与一维数组是相同的。
看以下代码:

#include 
int main()
{
 int arr[3][4] = {0};
 int i = 0;
 for(i=0; i<3; i++)
 {
 int j = 0;
 for(j=0; j<4; j++)
 	{
	 arr[i][j] = i*4+j;
 	}
 }
 for(i=0; i<3; i++)
 {
 int j = 0;
 for(j=0; j<4; j++)
 {
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
 return 0;
}

结果:
在这里插入图片描述
解释:二维数组是从0 0下标开始的,到最后一个元素下标3 3,利用两个for循环嵌套遍历,得出结果。

数组名

二维数组的数组名指向的是第一行,+1的话就是指向第二行;
C语言:数组(详解)_第10张图片
C语言:数组(详解)_第11张图片

数组越界

当我们建好一个数组后,并对它进行了初始化,就表示它的空间内存就已经是确定的了,当在访问时,如果下标引用超过范围时,就是越界访问了。C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以程序员写代码时要做好检查。
如:

#include 
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int i = 0;
    for(i=0; i<=10; i++)
   {
        printf("%d\n", arr[i]);//当i等于10的时候,越界访问了
   }
 return 0;
}

C语言:数组(详解)_第12张图片
这里最后一个数给出的是随机数。
C语言:数组(详解)_第13张图片

数组作为函数参数

由上面我们知道,数组名是一个指针,当数组名作为参数传递给一个函数实际就是传递了首元素地址过去,然后在函数中对该指针执行间接访问操作实现对数据的访问。由于数组是在内存中连续存放的,所以在函数中调用数组的形参时,能跟在主函数一样调用数组。但是,正因为数组名是指针,在函数中用sizeof计算数组大小的时候,往往出现错误,因为此时调用过去的是首元素地址。所以解决方法经常在使用数组作为参数时,会带上一个数组元素个数的变量
如:调用冒泡排序函数时,都会先在数组所在函数先计算好个数,再进行传参。
C语言:数组(详解)_第14张图片

void bubble_sort(int arr[], int sz)//参数接收数组元素个数
{
  int i = 0;
 for(i=0; i<sz-1; i++)
   {
        int j = 0;
        for(j=0; j<sz-i-1; j++)
       {
            if(arr[j] > arr[j+1])
           {
                int tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
           }
       }
   }
}
int main()
{
    int arr[] = {3,1,7,5,8,9,0,2,4,6};
    int sz = sizeof(arr)/sizeof(arr[0]);//先计算好个数
    bubble_sort(arr, sz);
    for(i=0; i<sz; i++)
   {
        printf("%d ", arr[i]);
   }
    return 0;
}

结果:0 1 2 3 4 5 6 7 8 9

结尾

好了,文章到这里就结束了。这里只是对数组一些简单入门介绍,希望对你有所帮助。
C语言:数组(详解)_第15张图片

你可能感兴趣的:(C语言,c语言,算法)