C语言数组

数组

        存放相同数据类型元素的集合

数据类型 数组名[数组大小]

        创建数组,数组元素个数需要是常量,C99标准才支持变长数组,可以使用变量定义数组元素个数(变长数组不能初始化)。

创建数组

char arr1[3];    // 字符数组,有3个元素,元素的类型是char
int arr2[4];     // 整型数组,有4个元素,元素的类型是int
int* arr3[5];    // 整型指针数组,有5个元素,元素的类型是int*

数组的初始化

// 初始化内容为数组个数,数组元素个数是4个,字符串还有一个'\0'
char arr1[] = "abc";

// 不完全初始化,只初始化了前面3个,剩下的默认为0
char arr2[10] = { 'a', 'b', 'c' };

// 初始化内容为数组个数,数组元素个数是3个
int arr3[] = { 1,2,3 };

// 不初始化,数组元素都是随机值
int arr4[4];

// 不完全初始化,值初始化了前面5个,剩下的默认为0
int arr4[10] = { 1,2,3,4,5 };

数组的使用

        []是下标引用操作符,有两个操作数,数组名和下标,用来访问数组元素的。

        不建议用第二种方式访问数组元素数据。

        下标是从0开始的,一般通过for循环遍历数组。

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3 };
	
	for (int i = 0; i < 3; ++i)
		printf("%d ", arr[i]);

	return 0;
}

        数组的大小能够通过sizeof(数组名)计算。

sizeof(数组名)        计算整个数组大小

sizeof(数组名[0])    计算数组元素大小

sizeof(数组名) / sizeof(数组名[0])        计算数组元素个数

        一般计算数组元素个数作为边界。

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3 };
	
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < sz; ++i)
		printf("%d ", arr[i]);

	return 0;
}

数组的存储

        元素的地址

         发现每个元素的地址相差4个字节,因为元素是int类型的,int类型的大小是4个字节,数组在内存中是连续存放的,随着数组下标的增长,元素的地址也在变大。

        当数组是char类型的时候,每个元素的地址相差1个字节。

指针访问数组元素

 

        将首元素的地址存放在一个指针变量中,直接打印数组的地址和通过指针打印数组的地址是一样的,p+i就是跳过i个元素,因为p指向的对象是int类型的,所以跳过i*4个字节。

        可以通过解引用指针遍历访问数组元素。

二维数组

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

创建二维数组

char arr1[3][4];    //3行4列的二维数组,数组元素是char类型的
int arr2[2][3];     //2行3列的二维数组,数组元素是int类型的

        二维数组不初始化也跟一维数组一样,元素都是随机值。 

二维数组的初始化

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

        arr1按顺序初始化二维数组,第一行初始完,初始化第二行第一个,剩下的默认为0。

        arr2每行初始化两个,剩下的默认为0。 

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

        二维数组可以根据初始化内容判断有多少行。但是不能根据初始化内容判断有多少列。 

二维数组的使用

        行和列的下标都是从0开始的。遍历打印二维数组。

        sizeof(arr2)计算的是整个二维数组的大小,sizeof(arr2[0])计算的是一行的大小,sizeof(arr2[0][0])计算的是二维数组元素的大小,可以算出行和列。 

        arr2[0]是找到二维数组第一行的地址,相当于找到的是数组名。想要访问这一行的元素,还需要使用下标继续访问,arr[0][0]访问第一行第一个元素。

二维数组的存储

        打印二维数组每个元素的地址。

        每个元素的地址相差4,二维数组在内存中也是连续存储的。本质是一块连续的空间模拟成二维数组。

        前面三个存储第一行的数据,后面三个存储第二行的数据。

        二维数组的数组名+1,跳过第一行3*4个字节,到第二行的地址。 

数组越界

        数组的下标是有范围的,n个元素的数组,下标是从0开始,到n-1。小于0,大于n-1,去访问数组元素,都是数组越界访问数据,这是错误的行为。

冒泡排序

        排升序,依次比较两个相邻的元素,如果当前的元素比后面一个大,交换数据,每一趟排序,都会正确排好一个位置(最后一个,排一趟少一个),直到没有相邻元素需要交换,排序完成。核心思想是交换数据。

排升序

5 4 3 2 1        比较第1个数和第2个数,第1个数大,两数交换

4 5 3 2 1        比较第2个数和第3个数,第2个数大,两数交换

4 3 5 2 1        比较第3个数和第4个数,第3个数大,两数交换

4 3 2 5 1        比较第4个数和第5个数,第4个数大,两数交换

4 3 2 1 5        一趟排序结束,排好一个数,下一趟就少排序一个数。

...

1 2 3 4 5        结果

#include <stdio.h>
int main()
{
	int arr[] = { 5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	// sz(5)个元素只需要排序sz-1(4)趟,每一趟排序好一个位置
	// 最后剩下的一个就是有序的
	for (int i = 0; i < sz - 1; ++i)
	{
        // 定义一个flag判断是否有交换数据
        bool flag = true;
		// sz(5)个数排序,第一趟需要排序sz-1(4)次
		// 剩下4个数,第二趟就需要排序sz-1-1(3)次
		// i是变化的数,如果写成sz-1-i满足需求
		for (int j = 0; j < sz - 1 - i; ++j)
		{
			if (arr[j] > arr[j + 1])
			{
                flag = false;
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
        // 如果没有进行交换数据,证明该数组已经有序,结束循环
        if (flag)
            break;
	}
	// 打印数据
	for (int i = 0; i < sz; ++i)
		printf("%d ", arr[i]);
	return 0;
}

        如果数组本身就是有序的,可以定义一个判断条件,如果没有进行交换数据,结束循环。 

函数

        如果想实现一个功,最好能写成函数,不要在main函数直接写。

#include <stdio.h>
#include <stdbool.h>
// 需要传数组元素个数
void bubble_sort(int arr[], int sz)
{
    // sz个元素需要排序sz-1趟
	for (int i = 0; i < sz - 1; ++i)
	{
        bool flag = true;
        // sz个数,排序sz-1次,每次排序一个数,下一趟少排一个数
		for (int j = 0; j < sz - 1 - i; ++j)
		{
            // 依次比较
			if (arr[j] > arr[j + 1])
			{
                flag = false;
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
        
        if (flag)
            break;
	}
}

int main()
{
	int arr[] = { 5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);
	// 打印数据
	for (int i = 0; i < sz; ++i)
		printf("%d ", arr[i]);
	return 0;
}

        注: 数组名本质上就是地址,数组名作为实参,并不会将整个数组传过去,传的是首元素的地址,形参得到的是地址。不能通过指针(地址)计算数组元素个数,所以需要将数组元素个数传给冒泡排序函数。

数组名

        数组名是数组首元素的地址,但是有两个列外。

1.sizeof(数组名)        这里的数组名表示的是整个数组,计算的是整个数组的大小。

2.&数组名                 这里的数组名表示的是整个数组,取出的是整个数组的地址,对该地址加1,跳过的是整个数组大小。

        打印的地址是16进制数。 

        arr和arr+1相差一个整型大小,4个字节;&arr[0]和&arr[0]+1相差一个整型大小,4个字节。

        &arr和&arr+1相差五个整型大小,20个字节,&arr+1跳过的整个数组。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值