您的位置:首页 > 其它

29_指针和数组分析(下)

2018-03-27 13:57 295 查看
关键词:下标形式VS指针形式、数组和指针的不同点、a和&a的区别、数组参数

问题: 数组名可以当作常量指针使用,那么指针是否也可以当作数组来使用呢?

(1) 通过下标的形式访问数组中的元素

int main()
{
int a[5] = {0};
a[1] = 3;
a[2] = 5;

return 0;
}


(2) 通过指针的形式访问数组中的元素

int main()
{
int a[5] = {0};
*(a + 1) = 3;
*(a + 2) = 5;

return 0;
}


1. 下标形式VS指针形式

(1) 指针以固定增量在数组中移动,效率高于下标的形式;

(2) 指针增量为1,且硬件具有硬件增量模型时,效率更高;

(3)下标形式与指针形式的转换:a
<==> (a + n) <==> (n + a) <==> n[a]

note: 现代编译器的生成代码优化率已大大提高,在固定增量时,下标形式的效率已经和指针形式的相当;但从代码可读性和代码维护性的角度来看,下标形式的更优。

#include<std
4000
io.h>

int main()
{
int a[5] = {0};
int* p = a;
int i = 0;

for(i=0; i<5; i++)
{
p[i] = i + 1;
}

for(i=0; i<5; i++)
{
printf("a[%d] = %d\n", i, *(a + i));
}

printf("\n");

for(i=0; i<5; i++)
{
i[a] = i + 10;   // 通过等价代换公式赋值 ==> a[i] = i + 10;
}

for(i=0; i<5; i++)
{
printf("p[%d] = %d\n", i, p[i]);
}

return 0;
}


输出结果:

a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5

p[0] = 10
p[1] = 11
p[2] = 12
p[3] = 13
p[4] = 14


总结: 通过上面程序验证可知:指针可以当作数组名使用。

2. 数组和指针的不同点

extern.c
a[5] =  {0};


2.c
#include<stdio.h>

int main()
{
extern int a[5];    // 定义为数组的形式

printf("&a = %p\n", &a);
printf("a = %p\n", a);
printf("*a = %d\n", *a);
}


输出结果:

&a = 0x804a024
a = 0x804a024
*a = 0


修改:将数组的形式定义为指针的形式

#include<stdio.h>

int main()
{
extern int* a;    //   定义为指针的形式

printf("&a = %p\n", &a);
printf("a = %p\n", a);
printf("*a = %d\n", *a);
}


输出结果

&a = 0x804a024
a = 0x1
Segmentation fault


总结:这两个程序对比可知得到,数组名不是指针,只是我们在通常情况下将数组名作为常量指针来使用。

3. a和&a的区别

(1) a为数组首元素的地址

(2) &a为整个数组的地址

(3) 区别在于指针运算

a + 1 <==> (unsigned int)a + sizeof(* a)

&a + 1 <==> (unsigned int)a + sizeof(* &a) <==> (unsigned int)a + sizeof(a)

#include<stdio.h>

int main()
{
int a[5] = {1, 2, 3, 4, 5};

int* p1 = (int*)(&a + 1);      // p1指向数组最后一个元素的后一个地址
int* p2 = (int*)((int)a + 1);  // p2指向的值为:将a的地址值强制转化为int型后+1
int* p3 = (int*)(a + 1);       // p3指向第二个元素

printf("%d, %d, %d \n", p1[-1], p2[0], p3[1]);

return 0;
}


输出结果:

5, 33554432, 3


总结: 用-1访问数组指的是访问数组名的上一个元素;

4. 数组参数

数组作为函数参数时,编译器将其编译成对应的指针

void f(int a[]) <==> void f(int* a)

void f(int a[5]) <==> void f(int* a)

总结:一般情况下,当定义的函数中有数组参数时,需要定义另一个参数来标识数组的大小。

#include<stdio.h>

void fun1(char a[5])
{
printf("In func1: sizeof(a) = %d\n", sizeof(a));

*a = 'a';

a = NULL;
}

void fun2(char b[])
{
printf("In func2: sizeof(b) = %d\n", sizeof(b));

*b = 'b';

b = NULL;
}
int main()
{
char array[10] = {0};

fun1(array);
printf("array[0] = %c\n", array[0]);

fun2(array);
printf("array[0] = %c\n", array[0]);

return 0;
}


输出结果:

In func1: sizeof(a) = 4
array[0] = a
In func2: sizeof(b) = 4
array[0] = b


总结: 通过fun1中的a = null 和 fun2中的b = null 可知数组作为函数传递的为指针。

小结

(1) 数组名和指针仅使用方式相同,注意数组名的本质不是指针; 指针的本质不是数组;

(2)数组名并不是数组的地址,而是数组首元素的地址

(3)函数的数组参数退化为指针

声明:此文章为本人在学习狄泰软件学院《C语言深度解析》所做的笔记,文章中包含狄泰软件资料内容一切版权归狄泰软件所有!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: