題記:
關于指針,推薦看一下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
|
|