目录
1. 一维数组的创建和初始化。
1.1 数组的创建
数组是一组相同类型元素的集合。
数组的创建方式:数组创建的实例:
type_t arr_name [const_n];
//type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小
数组创建的实例:
//一维数组的创建和初始化
//____type_t—表示元素类型___const_n表示常量表达式
//int main()
//{
// int arr[10]={1,2,3,4,5,6,7,8,9,10};
// int arr1[100] = { 0 };
//
// //const int n = 10;//C里叫常变量不支持,c++里面叫常量支持
// /*int n = 10;
// scanf("%d",&n);
// int arr2[n];*/
// //c99中引入了变长数组的概念,允许数组的大小用变量来表示
// //如果编译器不支持c99中的变长数组,就不能使用
// //vs不支持变长数组
// return 0;
注:数组创建,在C99标准之前,[]中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念。
1.2 数组的初始化
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。
int a;//全局变量不初始化,它的值默认为零,包括静态变量
int main()
{
static int b;//静态变量即在静态区的变量不初始化,默认为零
int arr[10] = { 1,2,3,4 };//不完全初始化
int arr2[] = { 1,2,3,4 };//数组大小为4
//数组的大小不初始化,会自动根据内容来确定
//char ch[] = { 'a','b','c' };
//char ch2[] = { 'a',98,'c' };
int arr3[10];//不初始化,都是随机值;
//int hhh;//未初始化的内存,报错or随机值
printf("%d %d\n", a, b);
return 0;
}
数组在创建的时候如果想不指定数组的确定的大小就得初始化。数组的元素个数根据初始化的内容来确定。
但是对于下面的代码要区分,内存中如何分配。
int main()
{
//char arr1[5] = { 'a','b','c' };//abc\0\0
//char arr2[5] = "abc";//abc\0\0
char arr1[] = { 'a','b','c' };//abc
char arr2[] = "abc";//abc\0
return 0;
}
1.3 一维数组的使用
对于数组的使用我们之前介绍了一个操作符:[],下标引用操作符。它其实就数组访问的操作符。我们来看代码:
#include<stdio.h>
int main()
{
int arr[100] = { 1,2,3,4,5,6 };
printf("%d\n", arr[4]);//[]下标引用操作符;arr,4是[]的两个操作数
printf("%d\n", sizeof(arr));//结果为400个字节
printf("%d\n", sizeof(arr[0]));//结果为4,一个元素大小
int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数的写法
for (int i = 0; i < sz; i++)
{
arr[i] = i + 1;
}
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
总结:
1. 数组是使用下标来访问的,下标是从0开始。
2. 数组的大小可以通过计算得到。
1.4 一维数组在内存中的存储
#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]);
for (int i = 0; i < sz; i++)
{
printf("arr[%d]<==>%p\n", i, &arr[i]);
//整数数组一个元素的大小是4个字节
/* arr[0] <= = > 0000007CB47BF4D8
arr[1] <= = > 0000007CB47BF4DC
arr[2] <= = > 0000007CB47BF4E0
arr[3] <= = > 0000007CB47BF4E4
arr[4] <= = > 0000007CB47BF4E8
arr[5] <= = > 0000007CB47BF4EC
arr[6] <= = > 0000007CB47BF4F0
arr[7] <= = > 0000007CB47BF4F4
arr[8] <= = > 0000007CB47BF4F8
arr[9] <= = > 0000007CB47BF4FC*/
}
char arr1[10] = { "abcdefghi" };
//打印每个元素的地址
int sz1 = sizeof(arr1) / sizeof(arr1[0]);
for (int i = 0; i < sz1; i++)
{
printf("arr[%d]<==>%p\n", i, &arr1[i]);
//字符数组一个元素的大小是1个字节
/*arr[0] <= = > 0000003E2033FAA8
arr[1] <= = > 0000003E2033FAA9
arr[2] <= = > 0000003E2033FAAA
arr[3] <= = > 0000003E2033FAAB
arr[4] <= = > 0000003E2033FAAC
arr[5] <= = > 0000003E2033FAAD
arr[6] <= = > 0000003E2033FAAE
arr[7] <= = > 0000003E2033FAAF
arr[8] <= = > 0000003E2033FAB0
arr[9] <= = > 0000003E2033FAB1*/
}
//一维数组在内存中是连续存放的
//随着数组下标的增长,地址是由高到低变化的
return 0;
}
总结:
一维数组在内存中是连续存放的
随着数组下标的增长,地址是由低到高变化的
//2.打印数组地址的第二种方法
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* pa = &arr[0];
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
printf("arr[%d]<==>%p<==>%p\n", i, &arr[i],pa + i);
}
printf("\n\n");
/* arr[0] <= = > 000000E60233FA18 <= = > 000000E60233FA18
arr[1] <= = > 000000E60233FA1C <= = > 000000E60233FA1C
arr[2] <= = > 000000E60233FA20 <= = > 000000E60233FA20
arr[3] <= = > 000000E60233FA24 <= = > 000000E60233FA24
arr[4] <= = > 000000E60233FA28 <= = > 000000E60233FA28
arr[5] <= = > 000000E60233FA2C <= = > 000000E60233FA2C
arr[6] <= = > 000000E60233FA30 <= = > 000000E60233FA30
arr[7] <= = > 000000E60233FA34 <= = > 000000E60233FA34
arr[8] <= = > 000000E60233FA38 <= = > 000000E60233FA38
arr[9] <= = > 000000E60233FA3C <= = > 000000E60233FA3C*/
char arr1[10] = { "abcdefghi" };
//打印每个元素的地址
int sz1 = sizeof(arr1) / sizeof(arr1[0]);
char *pb = &arr1[0];
for (int i = 0; i < sz1; i++)
{
printf("arr[%d]<==>%p<==>%p\n", i, &arr1[i],pb+i);
}
/* arr[0] <= = > 00000019E9CFFBE8 <= = > 00000019E9CFFBE8
arr[1] <= = > 00000019E9CFFBE9 <= = > 00000019E9CFFBE9
arr[2] <= = > 00000019E9CFFBEA <= = > 00000019E9CFFBEA
arr[3] <= = > 00000019E9CFFBEB <= = > 00000019E9CFFBEB
arr[4] <= = > 00000019E9CFFBEC <= = > 00000019E9CFFBEC
arr[5] <= = > 00000019E9CFFBED <= = > 00000019E9CFFBED
arr[6] <= = > 00000019E9CFFBEE <= = > 00000019E9CFFBEE
arr[7] <= = > 00000019E9CFFBEF <= = > 00000019E9CFFBEF
arr[8] <= = > 00000019E9CFFBF0 <= = > 00000019E9CFFBF0
arr[9] <= = > 00000019E9CFFBF1 <= = > 00000019E9CFFBF1*/
return 0;
}
总结:
可知整型数组一个元素大小为4个字节;字符数组一个元素大小为1个字节。
通过指针变量访问数组地址时,
整型数组每增加4个字节便可以访问到下个数组;因此使用int *指针每次加1跳过四个字节
字符数组每增加1个字节才可访问到下个数组。 因此使用char *指针每次加1跳过一个字节
float arr[ ] //4
double arr[ ] //8
short arr[ ] //2
int arr[ ] //4
long int arrr[ ] //4
long long int arr[ ] //8
2. 二维数组的创建和初始化
2.1 二维数组的创建
#include<stdio.h>
int main()
{
int arr[5][3];
char ch[5][7];
return 0;
}
2.2 二维数组的初始化
#include<stdio.h>
int main()
{
//int arr[3][5]={1,2,3,4,5,6};//不完全初始化
//先放完一行,剩下默认初始化为零
//int arr[3][5] = { {1,2},{3,4},{5,6} };
//1,2在第一行,3,4在第二行,5,6在第三行
//int arr[][5] = { 1,2,3,4,5,6 };
//放完第一行后,剩下6放在第二行,初始化两行
//int arr[3][] = { 1,2,3,4,5,6 };//但是列不初始化不可用
//int arr[][5]= { {1,2},{3,4},{5,6} };
//初始化三行,一行除了给定的两个数,剩下默认初始化为零
char ch[5][7];
return 0;
}
2.3 二维数组的使用
#include<stdio.h>
int main()
{
int arr[][5] = { {1,2},{3,4},{5,6} };
int i = 0;
for (i = 0; i < 3; i++)// 0 1 2
{
for (int j = 0; j < 5; j++)
{
printf("%d", arr[i][j]);
}
printf("\n");
}
return 0;
}
#include<stdio.h>
//sizeof(arr) / sizeof(arr[0])
//表示整个数组的大小/第一行整体的大小;就可以算出有几行
// sizeof(arr[0])/sizeof(arr[0][0])
//表示第一行整体的大小/一个元素的大小;就可以算出有几列
int main()
{
int arr[][5] = { {1,2},{3,4},{5,6} };
int i = 0;
for (i = 0; i <sizeof(arr)/sizeof(arr[0]); i++)// 0 1 2
{
for (int j = 0; j < sizeof(arr[0])/sizeof(arr[0][0]); j++)
{
printf("%d", arr[i][j]);
}
printf("\n");
}
return 0;
}
2.4 二维数组在内存中的存储
#include<stdio.h>
int main()
{
int arr[3][5] = { {1,2},{3,4},{5,6} };
int i = 0;
int sz1 = sizeof(arr) / sizeof(arr[0]);
int sz2 = sizeof(arr[0]) / sizeof(arr[0][0]);
for (i = 0; i <sz1 ; i++)// 0 1 2
{
for (int j = 0; j <sz2 ; j++)
{
printf("&arr[ %d ][ %d ] = %p\n",i,j,&arr[i][j]);
}
printf("\n");
}
return 0;
}
二维数组,在内存中也是连续存放的;
C语言支持多维数组;
3. 数组越界
数组的下标是有范围限制的。
数组的下标规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。
所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。
C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,
//数组越界访问
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
//0~9
for (i = 0; i <= 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
所以程序员写代码时,最好自己做越界的检查。
二维数组的行和列也可能存在越界。
4. 数组作为函数参数
往往我们在写代码的时候,会将数组作为参数传个函数,比如:我要实现一个冒泡排序(这里要讲算法思想)函数
将一个整形数组排序。
那我们将会这样使用该函数:
4.1 冒泡排序函数的错误设计
10个数字进行9趟冒泡排序
//冒泡排序
#include<stdio.h>
//void bubble_sort(int arr[],int n)
void bubble_sort(int* arr, int n)
{
//int sz = sizeof(arr) / sizeof(arr[0]);
//arr传递的是首元素地址,并不自动创建数组;
int i = 0;//趟数
for (i = 0; i < n - 1; i++)
{
int j = 0;
for (j = 0; j <n-1-i ; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
//在此传参时传递的时数组名arr
//arr—表示的首元素地址
//相当于&arr[0]
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr,sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
//在绝大部分情况下:数组名就是数组首元素的地址
//有两个列外
//1.sizeof(数组名),数组名不是首元素的地址,数组名表示整个数组,计算的是整个数组的大小
//2.&数组名,数组名不是首元素的地址,数组名表示整个数组,取出的时整个数组的地址
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n\n", arr+1);
printf("%p\n", &arr[0]);
printf("%p\n\n", &arr[0] + 1);
printf("%p\n", &arr);
printf("%p\n\n", &arr+1);
printf("%d\n", sizeof(arr));
/* 000000DA58FCF6C8
000000DA58FCF6CC //增加4,数组名就是首元素地址
000000DA58FCF6C8
000000DA58FCF6CC //增加4
000000DA58FCF6C8
000000DA58FCF6F0 //增加40,&数组名表示整个数组
40*/
return 0;
}
//在绝大部分情况下:数组名就是数组首元素的地址
//有两个列外
//1.sizeof(数组名),数组名不是首元素的地址,数组名表示整个数组,计算的是整个数组的大小
//2.&数组名,数组名不是首元素的地址,数组名表示整个数组,取出的时整个数组的地址
//优化
void bubble_sort(int arr[],int n)
{
int i = 0;
for (i=0;i<n-1;i++)//控制趟数
{
int flag = 1;//假设已经有序
int j = 0;
for (j = 0; j < n-1-i; j++)//控制比较次数
{
if (arr[j] > arr[j + 1])
{
flag = 0;
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
if (1 == flag)
{
break;
}
}
}
int main()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr,sz);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}