★数组
数组:是一组相同类型的集合,有一维数组,二维数组(矩阵),三维数组和字符数组。
●一维数组
一维数组的创建:直接上例子(int arr1[10])。注:数组在创建的时候,[ ]中要给常量猜可以,不能使用变量。
◆陷阱:const关键字修饰的变量在C语言中是具有常属性的变量,依然是一个变量,不可以放在数组的[ ]中;但是在C++中const修饰的变量是一个常量,可以放在数组的[ ]中。
一维数组的初始化:在创建数组的同时给数组的内容一些合理初始值。(下面是例子:)
int arr1[10]={1,2,3} //数组的初始值为1,2,3,0,0,0,0,0,0,0 int arr2[]={1,2,3,4} //数组的初始值为1,2,3,4 int arr3[5]={1,2,3,4,5} char arr4[]={'a','b','c'} char arr5[]="abcdef"
◆陷阱:
char arr1[]="abc"//可以以%s形式打印,用sizeof计算值为4,因为还有'\0'字符结束标志 char arr2[3]={'a','b','c'};//不能以%s形式打印,因为没有'\0'字符结束标志,打印出来的结果为随机值 char *p="abcdef"//p为一个指针变量,它存的是首元素a的地址
一维数组的使用:
1.数组的使用是通过下标来访问的,下标是从0开始的。
2.数组的大小可以通过sizeof(arr)/sizeof(arr[0])求得。
一维数组在内存中的存储:数组在内存中是连续存放的(请看下面例子的输出结果是什么?)
#include<stdio.h> int main() { int arr[5] = { 0 }; int i = 0; for (i = 0; i < sizeof(arr) / sizeof(arr[0]);i++)\ { printf("&arr[%d]=%p\n", i, &arr[i]); } system("pause"); return 0; }
输出结果:
一维数组的指针访问:请看下面的例子
#include<stdio.h> #include<windows.h> int main() { int arr[10] = { 0 }; int i = 0; int *p = arr;//将数组的首元素赋给指针变量p for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { *(p + i) = i;//(p+i)是第i个元素的地址 } for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { printf("%d\n", *(p + i)); } system("pause"); return 0; }
◆一维数组的数组名其实就是数组首元素的地址,通过对数组名+整数的运算,可以获得到数组每个元素的地址。
◆
陷阱:
printf("%p\n",arr);输出的是数组首元素的地址 printf("%p\n",&arr[0]);输出的是数组首元素的地址 printf("%p\n",&arr);输出的是数组的地址对它进行加1操作跳过整个数组
●二维数组
二维数组的创建:(直接上例子)
int arr[3][4]; char arr[3][5]; double arr[2][4];
二维数组的初始化:(直接上例子)
int arr[3][4]={1,2,3,4}; int arr[3][4]={{1,2},{4,3}}; int arr[][4]={{2,3},{4,5}};
◆陷阱:在二维数组初始化的时候,因为它在内存中也是连续存储的,所以可以看成是一行,可以根据列确定数组中的元素。因此初始化的时候行可以省略,但是列一定不能省略。
二维数组的使用:
#include<stdio.h> #include<windows.h> int main() { int arr[3][4] = { 0 }; int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 4; j++) { arr[i][j] = i * 4 + j + 1;//给二维数组赋值1-12 } } for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 4; j++) { printf("%d ", arr[i][j]); } } system("pause"); return 0; }
◆二维数组的使用也是根据下标的方式使用的。
二维数组在内存中的存储:在内存中连续存储(大概是下面这幅图的样子!)
一维数组的指针访问:请看下面的例子
#include<stdio.h> int main() { int arr[3][4] = { 0 }; int *p = &arr[0][0];//数组首元素的地址 int i = 0; for (i = 0; i < 12; i++) { *(p + i) = i;//(p+i)是数组i个元素的地址,然后在解引用,给数组每个元素赋值 } for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 4; j++) { printf("%d ", arr[i][j]); } } return 0; }◆陷阱:数组名代表整个数组只有两种情况:
①sizeof(数组名),用来求数组的大小。
②&数组名,取出来的是整个数组的地址
前方高能!!!接下来的文章是关于数组的运算,非常重要哦。
▲有关数组的运算
一维数组:
#include<stdio.h> int main() { int a[] = { 1, 2, 3, 4 }; printf("%d\n", sizeof(a));// 16 这里的a代表的是整个数组 printf("%d\n", sizeof(a+0));//4 首元素的地址 printf("%d\n", sizeof(*a));//4 a[0]类型所占大小 printf("%d\n", sizeof(a+1));//4 第二个元素的地址 printf("%d\n", sizeof(a[1]));//4 a[1]类型所占大小 printf("%d\n", sizeof(&a));//4 整个数组的地址,这里和首元素的地址相同,但进行加1操作就不一样了 printf("%d\n", sizeof(*&a));//16 对数组的地址进行解引用 printf("%d\n", sizeof(&a+1));//4 指向4后边的指针(地址) printf("%d\n", sizeof(&a[0]));//4 a[0]的地址 printf("%d\n", sizeof(&a[0]+1));//4 a[1]的地址 return 0; }
字符数组:
#include<stdio.h> #include<string.h> int main() { char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' }; //sizeof printf("%d\n", sizeof(arr));//6 数组有6个字符,没有'/0',都是字符类型 printf("%d\n", sizeof(arr+0));//4 数组首元素的地址 printf("%d\n", sizeof(*arr));//1 a的类型所占空间 printf("%d\n", sizeof(arr[1]));//1 b的类型所占空间 printf("%d\n", sizeof(&arr));//4 整个数组的地址 printf("%d\n", sizeof(&arr+1));//4 指向f后边的指针 printf("%d\n", sizeof(&arr[0]+1));//4 第二个元素的地址 //strlen printf("%d\n", strlen(arr));//随机值 数组没有'\0'结束标志,停不下来 printf("%d\n", strlen(arr+0));//随机值 数组首元素的地址,没有'\0' printf("%d\n", strlen(*arr));//错误的表达式 strlen函数接受的是一个指针,而不是值 printf("%d\n", strlen(arr[1]));//错误的表达式 strlen函数接受的是一个指针,而不是值 printf("%d\n", strlen(&arr));//随机值 数组的地址,没有'\0' printf("%d\n", strlen(&arr+1));//随机值 指向f后边的指针 printf("%d\n", strlen(&arr[0]+1));//随机值 第二个元素的地址 return 0; }
#include<stdio.h> #include<string.h> int main() { char arr[] = "abcdef"; //sizeof printf("%d\n", sizeof(arr));//7 //数组一共有7个字符,包括'/0',他们的类型都是字符 printf("%d\n", sizeof(arr+0));//4 首元素的地址,指针变量为4个字节 printf("%d\n", sizeof(*arr));//1 arr[0],a的类型为字符 printf("%d\n", sizeof(arr[1]));//1 b的类型为字符 printf("%d\n", sizeof(&arr));//4 整个数组的地址 printf("%d\n", sizeof(&arr+1));//4 指向arr数组后的指针 printf("%d\n", sizeof(&arr[0]+1));//4 第二个元素的地址 //strlen printf("%d\n", strlen(arr));//6 不算'\0',有6个字符 printf("%d\n", strlen(arr+0));//6 数组首元素的地址 printf("%d\n", strlen(*arr));//错误的表达式 strlen函数接受的是一个指针,而不是值 printf("%d\n", strlen(arr[1]));//错误的表达式 strlen函数接受的是一个指针,而不是值 printf("%d\n", strlen(&arr));//6 数组的地址,这里和首元素地址相同但意义不同 printf("%d\n", strlen(&arr+1));//随机值 指向f后边的指针 printf("%d\n", strlen(&arr[0]+1));//5 第二个元素的地址 }
#include<stdio.h> #include<string.h> int main() { char *p = "abcdef"; //sizeof printf("%d\n", sizeof(p));//4 p是一个指针变量,为a的地址 printf("%d\n", sizeof(p+1));//4 第二个元素的地址 printf("%d\n", sizeof(*p));//1 *p=a,a的类型为char printf("%d\n", sizeof(p[0]));//1 相当于对p进行解引用操作 printf("%d\n", sizeof(&p));//4 指针变量p的地址,为二级指针 printf("%d\n", sizeof(&p+1));//4 还是地址 printf("%d\n", sizeof(&p[0]+1));//第二个元素的地址 //strlen printf("%d\n", strlen(p));//6 从首元素开始数到'\0'结束 printf("%d\n", strlen(p + 1));//5 第二个元素的地址,从第二个开始数 printf("%d\n", strlen(*p));//错误的表达式 strlen函数接受的是一个指针,而不是值 printf("%d\n", strlen(p[0]));//错误的表达式 strlen函数接受的是一个指针,而不是值 printf("%d\n", strlen(&p));//随机值,二级指针不能确定 printf("%d\n", strlen(&p + 1));//随机值 printf("%d\n", strlen(&p[0] + 1));//5 第二个元素的地址 }
#include<stdio.h> #include<string.h> int main() { int a[3][4] = { 0 }; printf("%d\n", sizeof(a));//48 这里的数组名表示整个数组 printf("%d\n", sizeof(a[0][0]));//4 首元素的类型为int printf("%d\n", sizeof(a[0]));//16 可以把a[0]当做第一行数组的数组名 printf("%d\n", sizeof(a[0]+1));//4 a[0]降级成a[0][0]的地址,加1变成a[0][1]的地址 printf("%d\n", sizeof(a+1));//4 a降级成数组第一行的地址,在加1成第二行的地址 printf("%d\n", sizeof(&a[0]+1));//4 第二行的地址 printf("%d\n", sizeof(*a));//16 a降级成数组第一行的地址,在进行解引用操作,和sizeof(a[0])等价 printf("%d\n", sizeof(a[3]));//16 sizeof内部的表达式不运算,由a[0]推出a[3]的类型,和a[0]是等价的 return 0; }
数组作为函数参数:(请看下边的例子,这样可以吗?)
void binary_search(int arr[]); { int sz=sizeof(arr)/sizeof(arr[0]); .... .... }◆ 陷阱:数组作为函数参数的时候,不会把整个数组传递过去,而是把数组首元素的地址传递过去了,所以sizeof(arr)/sizeof(arr[0])这个计算值是1。如果要用到数组的长度,应该当做参数直接传给地址。这里的int arr[ ]表示的是指针,和int *arr等价。