目录
一、一维数组
1.一维数组的创建
数组的创建方式:type_t arr_name [const_n]
type_t 是指数组的元素类型 const_n 是一个常量表达式,用来指定数组的大小
下面通过代码来介绍数组的创建以及创建时所要注意的问题
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; //如果将其换成变量的形式
const int n = 10; //所以,如果不支持的话 ,用const也不能,因为在C语言里面const定义的是 长变量 也是一个变量
//但是在c++里面的话 const定义的是一个常量 跟C语言完全不一样 因此c++可以
scanf("%d", &n);//通过n来改变数组的大小
int arr[n]; //c99引入了变长数组(长度可变)的概念,允许数组的大小用变量来指定,如果编译器不支持c99中的变长数组,那就不能使用
//所以vs2022是不支持变长数组的
return 0;
}
2.一维数组的初始化
数组的初始化是指在创建数组的时候给数组赋一些值
不同类型的数组有不同类型的创建方式
具体的代码演示:
int arr[10] = { 1,2,3,4 };//指的是不完全初始化 ,指初始化了一部分,剩下的默认为0;
char arr1[] = { 'a','b','c' };
char arr2[] = { 'a',98,'c' }; // arr1[] arr2[] 其实是一样的 98对应的ASCII值就是98
//对数组进行初始化的时候 []里面的值是可以不用写的 这时候初始化的大小跟你赋的值的内容来定
char arr3[] = "abc";//这种数组的创建是有\0的,且不完全初始化的值剩余的是默认为 \0
当不初始化的时候,编译器会有自己默认规则
1.当不初始化的时候打印,系统会随机赋值。
2.全局变量跟静态变量的默认初始值均为0。
因为全局变量跟静态变量都是在内存的静态区里面创建的,这里面创建的值默认初始值为零 ,但是在栈区里面创建的值 如:局部变量和形式参数
下面通过代码来具体实现一维数组的输入与输出
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int arr4[10];
//下标 0 1 2 3 4 5
//写一个代码赋值1~10
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
//赋值
for (i = 0; i < sz; i++)
{
//arr4[i] = i + 1; //打印1~10
scanf("%d", &arr4[i]); //输入并输出
//或者使用
// scanf("%d", arr4+i); //输入并输出 这样就不需要&了
}
//打印
for (i = 0; i < sz; i++)
{
printf("%d ", arr4[i]);
}
//printf("%d\n", arr4[4]);//[]下标引用操作符,[]有两个操作数:arr,4
return 0;
}
3.一维数组在内存中的存储方式
一维数组在内存当中是连续存放的,随着数组下标的增长,地址是由低到高变化的
下面通过一串代码的运行来具体介绍
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//打印数组的每个元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int* p = &arr[0];
for (i = 0; i < sz; i++)
{
printf("arr[%d] = %p <====> %p\n", i, &arr[i],p+i); //p+1 是跳过一个整型 即跳过4个字节
//%p - 打印地址(16进制)
//%d - 打印整数(10进制)
}
//arr 数组名是指第一个元素的地址
return 0;
}
4.一维数组的数组名问题
二、二维数组
二维数组的创建与一维数组相差不大,具体通过下面的代码来具体介绍
1.二维数组的初始化
int arr[3][5]; //三行五列
int arr1[3][5] = { 1,2,3,4,5,6 }; //初始化1 不完全初始化
//int arr1[][5] = { 1,2,3,4,5,6 }; //初始化1 不完全初始化
//int arr1[3][] = { 1,2,3,4,5,6 }; //初始化1 不完全初始化 报错
//
//总结:行可以省略,但列不可以省略
int arr2[3][5] = { {1,2 }, {3, 4}, {5, 6} };//初始化2
//第一行1,2,0,0,0
//第二行3,4,0,0,0
//第三行5,6,0,0,0
通过代码来演示二维数组的输入与输出
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr3[3][5] = { {1,2 }, {3, 4}, {5, 6} };
int i = 0;
for (i = 0; i < 3; i++) //第i行
{
int j = 0;
for (j = 0; j < 5; j++) //第j列
{
printf("%d ", arr3[i][j]);
}
printf("\n");
}
return 0;
}
当然这里面的3,5也可以用sizeof来写
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(){
int i = 0;
for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) //第i行 解释:将arr全部除以第一行全部arr[0] 即为行数
{
int j = 0;
for (j = 0; j < sizeof(arr[0])/sizeof(arr[0][0]); j++) //第j列 解释: 将arr[0]的一行的全部除以第一个元素arr[0][0]即为行数的大小
{
printf("%d ", arr3[i][j]);
}
printf("\n");
}
return 0;
}
2.二维数组的存储方式
二维数组:在内存当中也是连续存放的,是一行一行放的 二维数组可以理解为一维数组的数组
通过代码演示介绍二维数组的存储方式
#include<stdio.h>
int main(){
int i = 0;
int* p = &arr3[0][0];
for (i = 0; i < sizeof(arr3) / sizeof(arr3[0]); i++)
{
int j = 0;
for (j = 0; j < sizeof(arr3[0]) / sizeof(arr3[0][0]); j++)
{
printf("&arr3[%d][%d] = %p\n ",i,j ,&arr3[i][j]);
}
printf("\n");
}
return 0;
}
三、数组下标越界问题
数组下标是有范围限制的,数组规定是从0开始的,如果数组有n个元素,那么最后一个数组元素的下标为n-1。
所以数组的下标小于0或者大于n-1,就是数组的越界访问了,超出数组的合法空间的访问。
四、习题: 写一个冒泡排序
代码:
void bubble_sort(int arr[],int sz)//arrp[]本质上是一个指针 也可以将其写成void bubble_sort(int* arr,int sz)
{
// int sz = sizeof(arr) / sizeof(arr[0]); //原因在这里 这里面传入过去数组之后,sz计算的大小为2
//原因就是数组名的问题
//趟数
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int flag = 1;//假设已经有序
//每一趟冒泡排序的一个过程
int j = 0;
for (j = 0; j <sz-1-i ; j++)
{
if (arr[j] > arr[j + 1])
{
flag = 0;
//交换
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
if (flag == 1)
{
break;//当排完第一趟的时候发现flag没有变,则说明是一个有序数列
}
}
}
}
int main()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
//写一个冒泡排序算法的函数,用来排序arr数组的内容
//bubble_sort(arr);
int sz = sizeof(arr) / sizeof(arr[0]);
//解决问题 把sz在主函数中定义 并且传到数组当中
bubble_sort(arr,sz); //数组在传参的时候一般都是传数组名
int i = 0;
//int sz = sizeof(arr) / sizeof(arr[0]); //但是这样的代码运行是有问题的
//原因是在函数内部
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
实现原理图:
通过上述代码具体引入了数组名的问题
五、数组名问题
绝大多数数组名就是数组首个元素的地址
有两个例外:
1. sizeof(数组名),数组名不是数组首个元素的地址,数组名表示整个数组 ,计算的是整个数组的地址
2. &数组名,数组名不是数组首个元素的地址,数组名表示的是整个数组,取出的是整个数组的地址
代码演示:
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%p\n", arr);
printf("%p\n", arr+1);
printf("%p\n", &arr[0]);
printf("%p\n", &arr[0]+1);
printf("%p\n", &arr);
printf("%p\n", &arr+1);
printf("%d \n", sizeof(arr));
return 0;
}
代码图解: