一、 一维数组
数组是存放同类型元素的集合
1.创建一维数组
数组类型 数组名[常量] = {value1,value2,... } ;
int main()
{
char arr1[20] = {0};
int arr2[10] = {0};
int arr3[] = {1,2,3,4,5};
char arr4[] = "abcde";
return 0;
}
创建时常见错误:
int main()
{
int arr[];
return 0;
}
注:数组创建,在C99标准之前,[] 中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念。
2.一维数组的使用
带有‘\0’的字符数组可以用字符串的格式打印
int main()
{
char str[]="abc";
char arr[]={'a','b','c','d','\0'};
printf("%s\n",str);
printf("%s\n",arr);
return 0;
}
不带有’\0’的字符数组和整型数组如何打印?
这里需要用到一维数组的下标,下标引用操作符[] ,就是数组访问的操作符。
include <stdio.h>
int main()
{
int arr[10] = {0};
int sz = sizeof(arr)/sizeof(arr[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;
}
1)数组是使用下标来访问的,下标是从0开始 2)数组的大小可以通过计算得到
int arr[10];
int sz = sizeof(arr)/sizeof(arr[0]);
sizeof为操作符,在计算数组大小时,不能放在函数内计算函数形参数组的大小,例如:
int Len(char str[])
{
int y = sizeof(str) / sizeof(str[0]);
return y;
}
int main()
{
char str[] = "abcde";
int sz = sizeof(str) / sizeof(str[0]);
printf("%d\n",sz);
int new_sz = Len(str);
printf("%d\n",new_sz);
return 0;
}
因为传给函数的数组名,不是整个数组,而是数组首元素地址,str为指针变量,sizeof(str)=4
3.一维数组在内存中的存储
上述问题中,将数组首地址传给函数,那么在函数内是如何以地址访问数组的呢?
这里需要学习一下一维数组在内存中的存储方式
int main()
{
int arr[10] = { 0 };
for (int i = 0; i < 10; i++)
{
printf("arr[%d] = %p\n" ,i ,&arr[i]);
}
return 0;
}
运行结果
随着数组下标的增长,元素的地址,也在有规律递增(和元素类型有关) 可以得出结论:数组元素在内存中是连续存放的
知道元素在内存中的存储情况,可以在函数中以地址访问数组元素了
void aces_arr(char* arr)
{
for (int i = 0; i < 5; i++)
{
printf("%d ",*(arr+i));
}
}
int main()
{
char arr[5] = {1,2,3,4,5};
aces_arr(arr);
return 0;
}
二、二维数组
与一维数组的定义唯一的不同是多了一个常量表达式2,其中,常量表达式1为第一维的长度,常量表达式2为第二维的长度。通常在处理二维数组的时候,为了便于理解,都将数组视为一个矩阵,常量表达式1表示矩阵的行数,而常量表达式2表示矩阵的列数。
1.创建二维数组
数组类型 数组名[常量1][常量2] = {value1,value2,...};
int arr[3][4] = {1,2,3,4};
int arr[3][4] = { {1,2},{4,5} };
int arr[][4] = {{1,2,3,4},{5,6,7,8}};
二维数组的访问也是通过下标访问的 //打印二维数组
int main()
{
int arr[3][4] = { 1,2,3,4,5,6 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("arr[%d][%d]=%d\n",i,j,arr[i][j]);
}
printf('\n');
}
return 0;
}
2.二维数组在内存中的存储
像一维数组一样,这里我们尝试打印二维数组的每个元素。
int main()
{
int arr[3][4] = { 1,2,3,4,5,6 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("&arr[%d][%d]=%p\n",i,j,&arr[i][j]);
}
}
return 0;
}
通过结果可以看到,二维数组在内存中也是连续存储的
三、数据越界
数组的小标是有范围限制的
数组的下标规定是从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;
for(i=0; i<=10; i++)
{
printf("%d\n", arr[i]);
}
return 0;
}
四、数组作为函数参数
数组作为调用函数的实参时,使用数组名 数组作为函数形参时,可以使用 int arr[] ,或者 int* arr 因为用数组名传参时,实质上传的是数组首元素地址,是个指针类型
void Print(int arr[], int sz)
{
for(int i = 0; i < sz;i++ )
{
printf("%d",arr[i]);
}
}
int main()
{
int arr[] = {1,2,3,4,5,6};
int sz = sizeof(arr)/sizeof(arr[0]);
Print(arr,sz);
return 0;
}
数组名是首元素地址(有两个例外)
1. sizeof(数组名),计算整个数组大小,sizeof内部单独放一个数组名,数组名表示整个数组
2. &数组名,取出的是整个数组的地址。&数组名,数组名表示整个数组**
|