Skip to content

数组

一维数组

数组名

数组明用来记住这个数组的属性,当数组在表达式中使用的时候,编译器会为他产生一个指针常量(不能修改的值)

只有在两种情况下数组名不是被当成指针使用

  • sizeof
  • &:产生一个指向数组的指针,而不是一个指向指针的指针,指针的类型是一个数组类型
C
  1 #include <stdio.h>                                                                    
  2 
  3 int main(){
  4     int a[10];
  5     int b[10];
  6     int *p;
  7     p = a;
  8     printf("p = a = %p\n", p);
  9     p = &a;
 10     printf("p = &a = %p\n", p);
 11     return 0;
 12 
 13 }
result:
/*
main.c: In function ‘main’:
main.c:9:11: warning: assignment to ‘int *’ from incompatible pointer type ‘int (*)[10]’ [-Wincompatible-pointer-types]
    9 |         p = &a;
      |           ^
jiao@jiao-virtual-machine:~/桌面/point_and_c/8$ ./a.out
*/
p = a = 0x7ffd32d61a60
p = &a = 0x7ffd32d61a60

非法使用

C
int a[10];
int b[10];
int *c;
b = a; //非法
a = c; //非法
a++;//非法,不能改变a的值
c = a; //合法

下标引用

array[subscript] <==> *(array + (subscript))

2[array] <==> *(array + 2) <==> array[2]

指针和下标

在可读性方面下标有优势,但是有可能会影响效率

C
int array[10],a;
for(a=0;a<10;a+=1)
    array[a]=0;//每次循环的时候进行一次乘法
C
int array[10],*ap;
for(ap=array,ap<array+10;ap++)//由于每次进行的乘法相同弄,所以只在编译的时候进行一次
	*ap = 0;

指针的效率

指针有着更高的效率,前提是被正确的使用,不要为了效率上的细微差距牺牲了可读性

示例: 把y中的数据复制到x中

C
#define SIZE 50
int x[SIZE];
int y[SIZE];
int i;
int *p1,*p2;

下标

C
void try1(void)
{
    for(i = 0; i<SIZE; i++)
        x[i] = y[i];
}

指针

C
void try2(void)
{
    for(p1 = x,p2 = y;p1 - x <size;)//两个指针相减的时候会进行除法
         *p1++=*p2++;
}
C
void try3(void)
{
    for(i=0,p1=x,p2=y;i<SIZE;i++)//在每次进行的时候需要把指针的值移到寄存器
        *p1++=*p2++;
}
C
void try4(void)
{
    register int *p1,*p2;
    register int i;
    for(i =0,p1=x,p2=y;i<SIZE;i++)
 		*p1++=*p2++;
}
C
void try5(void)
{
    register int *p1, *p2;
    for(p1=x,p2=y;p1<&x[SIZE];)//消除指针器
        *p1++ = *p2++;
}

总结

  • 当根据某个固定的量在数组中移动的时候,使用指针比使用下标效率更高

  • 声明为寄存器比静态内存和堆栈中的指针效率更高,但是当前的编译器会自动进行优化,并且做的比程序员更好

  • 通过测试一些已经初始化并调整的内容判断循环的终止就不需要单独的计数器

  • 在运算时候求值的表达式代价更高

声明数组参数

数组再传递的时候传递的是一个指针,在传递的时候不传递数组的长度

C
int strlen(char *string);  <==>  int strlen(char string[]);

初始化

  • 在声明的时候初始化int vector[5] = {1, 2, 3, 4, 5};

静态和自动初始化

和变量的初始化方式相似

应该考虑在每次进入函数的时候初始化一个数组是不是值得

不完整的初始化

  • 超出指定的空间 ==> 非法
  • 没有全部初始化 ==> 剩下的设置为0

字符串初始化

C
char message[] = "hello";
char message[] = {'h', 'e', 'l', 'l', 'o'};//初始化一个字符数组
char *message = "Hello";//初始化一个数组

多维数组

C
int a;
int b[10];
int c[6][10];//c是一个六元素的数组,每个元素是一个十元素的数组
int d[3][6][10];

多维数组的存储是按照右边的下标先变化的顺序进行存储的,但是应该尽量避免使用指针进行行的变化

一个二维数组的数组名是指向一个一维数组的指针

示例

C
int matrix[3][10];
matrix //指向第一个数组
matrix + 1 //指向第二个数组
*(matrix + 1) + 5//第二列的五个指针
*(*(matrix + 1) + 5)//第二列第五个的值
*(matrix[1] + 5)

指向数组的指针

错误示范 :int matrix[3][10], *mp = matrix;,实际的指针应该是int (*p)[10],p是一个指向整形数组的指针

如果要创建一个可以逐个访问的指针int *pi = &matrix[0][0];或者int *pi = &matrix[0];

**注:**不要使用int (*p)[ ] = matrix;初始化一个指针,系统会认为这是长度为0,在进行运算时会和长度相乘造成错误

作为函数参数的多维数组

多维数组的每个参数是一个数组,编译器要知道他的维数

C
void func(int (*mat)[10]);
void func(int mat[][10]);

初始化

C
int matrix[2][3] = {1, 2, 3, 4, 5, 6};
int matrix[3][5] = {
    {00, 01, 02, 03, 04},
    {10, 11, 12, 13, 14},
    {20, 21, 22, 23, 24}
}

QQ图片20220726233158

加不加花括号对结果没有影响。但是可以帮助理解,并且可以省略尾部的几个初始值

数组长度自动计算

只有第一维数组才可以省略,自动计算,后面的都需要添加

指针数组

每一个参数都是一个指针,可以用来存放字符串的首地址