您的位置:首页 > 职场人生

从一道面试题看指针与数组的区别

2010-06-09 21:38 204 查看
转自:http://blog.chinaunix.net/u/21948/showart_374560.html

题记:
关于指针,推荐看一下csdn飞天御剑流的《再再论指针》,相信对C语言指针会有一个更为清晰全面的理解。

指针是C语言的精华,它是一柄“双刃剑”,用的好与坏就看使用者的功力了。下面就一道面试题,看一下指针与数组的区别。

char
*p1,
*p2;
char
ch[12];
char **pp;
p1
= ch;
pp =
&ch;

p2 =
*pp;
问p1和p2是否相同


题目如上,找出其中的不妥之处。

首先,数组ch是没有初始化的。其次,一个比较隐含的地方是,数组名可以代表数组第一个元素的首地址,这个没有问题,但是,数组名并非一个变量,数组分配完成后,数组名就是固定的,地址也是固定的。这样导致的结果就是绝对不能把数组名当作变量来进行处理。上述题目中,pp=&ch,显然是把数组名当作指针变量来使用了,这样肯定出问题。

这个题目存在的两个问题,第一个问题比较简单,可以认为是粗心大意。但是第二个问题就是相当复杂了,扩展开来,那就是C语言中的精华中的指针和数组的联系与区别问题了。

下面分为两步,首先看一下指针和数组的区别方法,然后提出对上述程序的修改方案。

1 指针和数组的区别

(1)指针和数组的分配

数组是开辟一块连续的内存空间,数组本身的标识符(也就是通常所说的数组名)代表整个数组,可以使用sizeof来获得数组所占据内存空间的大小(注意,不是数组元素的个数,而是数组占据内存空间的大小,这是以字节为单位的)。举例如下:

#include <stdio.h>

int main(void)
{
char a[] = "hello";
int b[] = {1, 2, 3, 4, 5};

printf("a: %d/n",
sizeof(a));
printf("b memory size: %d bytes/n", sizeof(b));
printf("b elements: %d/n", sizeof(b)/sizeof(int));

return 0;
}


数组a为字符型,后面的字符串实际上占据6个字节空间(注意最后有一个/0标识字符串的结束)。从后面sizeof(b)就可以看出如何获得数组占据的内存空间,如何获得数组的元素数目。至于int数据类型分配内存空间的多少,则是编译器相关的。gcc默认为int类型分配4个字节的内存空间。

(2)空间的分配

这里又分为两种情况。

第一,如果是全局的和静态的
char *p =
“hello”;
这是定义了一个指针,指向rodata
section里面的“hello”,可以被编译器放到字符串池。在汇编里面的关键字为.ltorg。意思就是在字符串池里的字符串是可以共享的,这也是编译器优化的一个措施。

char a[] = “hello”;

这是定义了一个数组,分配在可写数据块,不会被放到字符串池。

第二,如果是局部的
char *p =
“hello”;
这是定义了一个指针,指向rodata
section里面的“hello”,可以被编译器放到字符串池。在汇编里面的关键字为.ltorg。意思就是在字符串池里的字符串是可以共享的,这也是编译器优化的一个措施。另外,在函数中可以返回它的地址,也就是说,指针是局部变量,但是它指向的内容是全局的。

char a[] = “hello”;

这是定义了一个数组,分配在堆栈上,初始化由编译器进行。(短的时候直接用指令填充,长的时候就从全局字符串表拷贝),不会被放到字符串池(同样如前,可能会从字符串池中拷贝过来)。注意不应该返回它的地址。

(3)使用方法

如果是全局指针,用于不需要修改内容,但是可能会修改指针的情况。

如果是全局数组,用于不需要修改地址,但是却需要修改内容的情况。

如果既需要修改指针,又需要修改内容,那么就定义一个数组,再定义一个指针指向它就可以了。

2 我编写的修改方案

[armlinux@lqm pointer]$ cat
pointer.c
/*
* Copyright 2007 (c), Shandong University
*
All rights reserved.
*
* Filename : test.c
* Description: about
pointer
* Author : Liu Qingmin
* Version : 1.0
* Date :
2007-08-27
*/

#include <stdio.h>

/*
* define a macro which is used to debug array mode
and pointer mode.
* if 1, debug array mode; else debug pointer mode.
*
You can change it according to your decision.
*/
#define
ARRAY_OR_POINTER 0

int main(void)
{
char *p1;
char *p2;
char **pp;

//test1

#if
ARRAY_OR_POINTER
char
ch[]
= "hello,
world!/n";

printf("%d, %d, %d, %d/n", sizeof(p1), sizeof(p2),

sizeof(pp), sizeof(ch));
#else
char *ch = "hello,
world!/n";

printf("%d, %d, %d, %d/n", sizeof(p1), sizeof(p2),

sizeof(pp), sizeof(ch));
#endif

//test2

p1 = ch;

#if
ARRAY_OR_POINTER
pp =
&p1;
#else
pp = &ch;
#endif

p2 = *pp;

if (p1 == p2) {
printf("p1 equals to p2/n");
}
else {
printf("p1 doesn't equal to p2/n");
}

return 0;
}


执行结果如下:

//
ARRAY_OR_POINTER为0时

[armlinux@lqm pointer]$ ./test
4,
4, 4,
4
p1 equals to p2
//
ARRAY_OR_POINTER为1时

[armlinux@lqm pointer]$ ./test
4,
4, 4,
15
p1 equals to p2


如果使用了数组定义方式,而又使用pp=&ch,那么就会出现类似下面的错误:

[armlinux@lqm
pointer]$ make
gcc -Wall -g -O2 -c -o pointer.o
pointer.c
pointer.c: In
function `main':
pointer.c:44: warning:
assignment from incompatible pointer type
gcc -Wall -g -O2 pointer.o -o
test
[armlinux@lqm pointer]$ ./test
4, 4, 4, 15
p1 doesn't equal to p2


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: