数组概念
在C语言中, 数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。
- 从内存角度,是一片连续的内存空间
数组初始化:
//在编译时明确指定全部元素为0
int a[10] = {0};
//在程序运行时,重置内存块为0
memset(a,0,sizeof(a));
数组元素个数在初始化的时候可以明确指出也可以根据初始化列表元素个数确定。
数组类型
- 数据类型:固定大小内存块的别名
- 指针类型:依赖于指针所指向的内存空间的大小
C语言中的数组有自己特定的类型:由元素类型和数组长度决定
例:int array[5]的类型为int [5]
可以重命名数组类型,并用新的数组类型名命名数组变量,使用typedef关键字进行重命名
typedef int (MYINT5)[5];//MYINT5表示一个含有5个元素的int类型的数组
MYINT5 array;//相当于int array[5];
数组名的技术盲点:
- 数组首元素的地址和数组地址是两个不同的概念
- 数组名代表数组首元素的地址,它是个常量
- 变量本质是内存空间的别名,一定义数组,就分配内存,内存就固定了。所以数组名起名以后就不能被修改了。
- 数组首元素的地址和数组的地址值相等,但只是值相等而已
C语言规定:
int a[10];
printf("得到整个数组的地址a: %d \n", &a);
printf("数组的首元素的地址a: %d \n", a);
数组指针类型
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_SIZE 5
int main(void)
{
int i = 0;
typedef int (myArray)[ARRAY_SIZE];//重命名一个数组类型myArray,表示int [5]
myArray array;//相当于int array[5];
myArray * p_array = NULL;//使用数组类型定义一个(myArray数组类型的)指针,用于指向一个myArray的变量
p_array = &array;//将指针变量指向数组类型的变量array,此时指针的步长是整个数组长度
for(i= 0;i<ARRAY_SIZE;i++){
(*p_array)[i] = i+1;//通过指针操作数组内存空间
}
for(i= 0;i<ARRAY_SIZE;i++){
printf("%d\n",(*p_array)[i]);
}
printf("Hello World!\n");
return 0;
}
直接定义数组指针变量
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_SIZE 5
int main(void)
{
int i = 0;
int (*p_array)[ARRAY_SIZE] = NULL;//告诉编译器 给我分配一个指针变量
//直接定义一个数组指针,相当于int (*p_myArray)[5];
int array[ARRAY_SIZE]={0};
p_array = &array;//将指针变量指向数组类型的变量array,此时指针的步长是整个数组长度
for(i= 0;i<ARRAY_SIZE;i++){
(*p_array)[i] = 2*i+2;//通过指针操作数组内存空间
}
for(i= 0;i<ARRAY_SIZE;i++){
printf("%d\n",(*p_array)[i]);
}
printf("Hello World!\n");
return 0;
}
多维数组
本质推演
多维数组名就是一个数组指针变量,指向除了最高维以外的剩余维数的数组
多维数组名是一个多级指针,取以后减少一级指针。同样的对于二级指针,取*以后变成一级指针,二级指针指向一块内存,常是一个数组,一级指针指向一个数组里面的元素。
n级指针的值和n-1级指针的值(就是地址相等)重合,拿二维数组来说,就是某一行整个行的地址(一个数组地址)和该行首元素的地址在相等,这是必然的,他们都是该片内存的起始位置,必然相等。但是他们的数据类型不一样。n级指针指向的内存块更多,n-1级指针指向的只是n级指针指向的内存块的一部分,常是其中的一个元素。
多维数组char a[i][j] ==> ((a+i)+j)转换技巧分析
示例程序
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void main()
{
int aaa[5][3];
for (i = 0; i<5; i++)
{
for (j = 0; j < 3; j++)
{
aaa[i][j] = j + i + 1;
}
}
for (i = 0; i<5; i++)
{
printf("\n");
for (j = 0; j < 3; j++)
{
printf("aaa[%d][%d] = %d\t",i,j, aaa[i][j]);
}
printf("\n");
}
printf("aaa地址:%d\n", aaa);
printf("aaa[0][0]地址:%d\n", &aaa[0][0]);
printf("aaa+1地址:%d\n", aaa+1);
printf("aaa[1][0]地址:%d\n", &aaa[1][0]);
printf("*(aaa+1)地址:%d\n", *(aaa + 1));
printf("*(aaa + 1)+1地址:%d\n", *(aaa + 1)+1);
printf("aaa[1][1]地址:%d\n", &aaa[1][1]);
printf("&aaa+1地址:%d\n", &aaa+1);
printf("aaa[4][2]地址:%d\n", &aaa[4][2]);
printf("hello...\n");
system("pause");
return;
}
运行结果
/**************
aaa[0][0] = 1 aaa[0][1] = 2 aaa[0][2] = 3
aaa[1][0] = 2 aaa[1][1] = 3 aaa[1][2] = 4
aaa[2][0] = 3 aaa[2][1] = 4 aaa[2][2] = 5
aaa[3][0] = 4 aaa[3][1] = 5 aaa[3][2] = 6
aaa[4][0] = 5 aaa[4][1] = 6 aaa[4][2] = 7
aaa地址:14023660
aaa[0][0]地址:14023660
aaa+1地址:14023672
aaa[1][0]地址:14023672
*(aaa+1)地址:14023672
*(aaa + 1)+1地址:14023676
aaa[1][1]地址:14023676
&aaa+1地址:14023720
aaa[4][2]地址:14023716
hello...
请按任意键继续. . .
************************/
a[i][j] === a[0+i][j] ==> *(a+i)[j] ===> *(a+i)[0 + j] ==> *( *(a+i) + j)
参数退化
void printArray01(int a[3][5]) //最不好的代码
{
int i, j, tmp = 0;
for (i=0; i<3; i++)
{
for (j=0; j<5; j++)
{
printf("%d ", a[i][j]);
}
}
}
void printArray02(int a[][5]) //二维数组是一个指向一维数组的指针。所以函数参数不用关心有多少行,只需要给出每一行有多少列确定指针步长即可
{
int i, j, tmp = 0;
for (i=0; i<3; i++)
{
for (j=0; j<5; j++)
{
printf("%d ", a[i][j]);
}
}
}
void printArray03( int (*b)[5]) //直接定义一个指向int [5]的数组指针
{
int i, j, tmp = 0;
for (i=0; i<3; i++)
{
for (j=0; j<5; j++)
{
printf("%d ", b[i][j]);
}
}
}
数组作函数参数
void f(int a[5]) ====》void f(int a[]); ===》 void f(int* a);
void g(int a[3][3])====》 void g(int a[][3]); ====》 void g(int (*a)[3]);
一维数组 char a[30]====》 指针 char*
指针数组 char *a[30] ====》指针的指针 char **a
二维数组 char a[10][30] ====》 数组的指针 char(*a)[30]
证明多维数组内存中是连续存储的
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void printfArray01(int *array, int size)
{
int i = 0;
for (i = 0; i < size; i++)
{
printf("%d ", array[i]);
}
}
void main()
{
int a[3][5];
int i, j, tmp = 1;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
a[i][j] = tmp++;
}
}
//把二维数组 当成 1维数组 来打印 证明线性存储
printfArray01(*a, 15);
printf("hello...\n");
system("pause");
return;
}
指针数组示例程序
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int searchKeyword(char * table[],int count,char *keyword,int *pos)
{
////字符串数组char *table[]做函数参数
int ret = 0;
int i = 0;
if (table == NULL || keyword == NULL || pos == NULL){
ret = -1;
return ret;
}
for (i = 0; i < count; i++){
if (strcmp(table[i], keyword) == 0){
*pos = i;
return ret;
}
}
if (i == count)
{
*pos = -1;
}
return ret;
}
#define DIM(a) (sizeof(a)/sizeof(*a))
void main()
{
char * src[] = {
"while",
"case",
"static",
"break"
};
int pos;
searchKeyword(src, DIM(src), "case", &pos);
printf("case is :%d\n",pos);
searchKeyword(src, DIM(src), "break", &pos);
printf("break is :%d\n", pos);
system("pause");
return;
}
指针数组的自我结束功能
指针数组最后一个元素用NULL或者’\0’或者0结尾可以表示指针数组结束,实现自我结束功能,而且三者实质一样
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void main()
{
int inum = 0;
int pos = 0;
int a[10];
int i = 0;
//指针数组 自我结束能力
char* c_keyword[] = {
"while",
"case",
"static",
"do",
'\0'
};
char* c_keyword2[] = {
"while",
"case",
"static",
"do",
0
};
char* c_keyword3[] = {
"while",
"case",
"static",
"do",
NULL
};
for (i = 0; c_keyword[i] != NULL; i++)
{
printf("%s\n", c_keyword[i]);
}
printf("\n....\n");
for (i = 0; c_keyword2[i] != NULL; i++)
{
printf("%s\n", c_keyword2[i]);
}
printf("\n....\n");
for (i = 0; c_keyword3[i] != NULL; i++)
{
printf("%s\n", c_keyword3[i]);
}
//三个运行效果一模一样
system("pause");
}