2013-07-13 38 views
-7

我想看看在下面一行更深:爲什麼我們要將字符串存儲在字符指針中,例如fopen();?

char* filename="file.txt";  

這是我做的,當我們使用fopen();

我的問題是:

  1. filename應該持有一個字符的地址(在酷睿2 36位)。爲什麼我們要在其中放置'字符串'?

  2. 爲什麼編譯器不會生成錯誤,因爲您可能正在存儲一個永遠不會存在的地址?

+6

請一般閱讀指針和C語言的入門知識。 –

+5

'core2duo中的36位'這些不是您將在C編程中看到的位。 –

+0

由於缺乏對該主題的最低限度知識而投票結束。 SO不能代替基礎教育。 –

回答

1

文件名應該保持一個字符的地址(酷睿2 36位),爲什麼我們都在上面放一個「字符串」?

可悲的事實是,我們不是。我們把一個指向字符串文字的第一個字符的指針放在它裏面。字符串"file.txt"的類型爲char[9],當分配給指針時,該字符串衰減爲char *。但是你應該將它分配給指向const char的指針,因爲修改它是非法的(導致未定義的行爲)。 Read this.

爲什麼編譯器不會產生錯誤,因爲您可能正在存儲一個永遠不會存在的地址?

不好意思,但是你說什麼樣的地址不存在?字符串文字中第一個字符的地址始終是明確有效的! (但即使它是 - 編譯器知道的語義很少,如果有的話),如果有可能使用一個無效的指針,它根本不可能總是警告你。當然,有時它可以,但是不管怎樣, t有很高的期望。)

1

請閱讀一些很好的C編程書籍,他們解釋了什麼是指針和數組。

字符串文字像"file.txt"char[]陣列(但你應該把它看成const char[]因爲像"abc"[1]='D';內分配字符串文字是undefined behavior有不好的味道,和gcc -Wall會警告你)。數組可以(通常)被理解爲指向其第一個單元格(索引爲0)的指針 - 換句話說,數組被衰減爲指針 - 因此,您可以將字符串文字分配給指針char

但是,數組不是C中的指針;例如sizeof某些數組是每個元素大小的合適倍數,特別是sizeof("abcde") == 6(因爲每個字符串文字中都有終止空字節)。但是一些指針與指向區域的大小無關,並且在大多數系統中,所有指針都具有相同的大小,即機器字的大小。

您需要明確地向編譯器詢問所有警告(例如,Linux上的gcc -Wall)以獲取它們。

+2

首先''file.txt「不是'const char []',它是'char [9]'。其次數組不是指針。他們是他們自己的類型。然而,它們可以腐爛成指針。 – Wiz

+1

我寫了「數組可以理解爲指針」而不是「數組是指針」,並且你不能寫''abc'[1] ='D';'因爲它是一個const char []'而不是'char [ ]' –

+0

@Wiz然而,你可能想與[這個人]交談(http://stackoverflow.com/questions/17604952/convert-int-to-int-pointers-address#comment25624644_17604991)。 – 2013-07-13 06:01:29

2

文件名應該保存一個字符的地址(core2Duo中的36位),爲什麼我們要在其中放入一個「字符串」?

表達式char* filename="file.txt";是一個有效的表達式。原因是C中字符串文字的類型爲char[N],很容易衰減爲char*,而char[N]char*是兼容的。因此,您可以將字符串地址分配給char*指針變量,就像您在此表達式中所做的那樣。

爲什麼編譯器不會產生錯誤,因爲您可能正在存儲一個永遠不會存在的地址?

請閱讀以下三點:

  • 它是一個有效的地址:

沒有,在表達char* filename="file.txt";filename被分配一個有效的地址。它的概念是這樣(假設地址以21開頭):

filename 21 22 23 24 25 26 27 28 29 
+---+  +------------------------------------+ 
|21 |---> |'f'|'i'|'l'|'e'|'.'|'t'|'x'|'t'|'\0'| 
+---+  +------------------------------------+ 

filename pointing to string, a valid address. 

和它不提供任何錯誤或警告:試試下面的代碼示例:

例如-1:

#include<stdio.h> 
int main(int argc, char **argv){ 
    char* filename = "filename.txt"; 
    printf("%s", filename); 
    return 0; 
} 

編譯:

:~$ gcc y.c -Wall -pedantic 
~$ ./a.out 
filename.txt 

沒有錯誤和戰爭中g,編譯和執行完美。

關於你我的回答評論:

字符串中C是有點複雜的數據結構則簡單的數值變量,如intcharfloat

在基本數據類型的情況:

int i = 5; You are assigning value 5, to variable i 
char c = 'A'; You are assigning value 'A' to char variable c. 
float f = 5.5f; You are assigning value 5.5f to float variable f. 

但對於字符串,當你這樣做:字符串"filename.txt"

char* filename = "filename.txt"; 

那麼你實際上是在指定地址爲char *指針變量filename

而如果你這樣做:

char filename[] = "filename.txt"; 
     //  ^notice [] in declaration 

然後要指定字符串「文件名。TXT「;爲CHAR filename[]的數組,這裏filename類型爲char[]

要了解雙方的聲明更deferences閱讀:What does sizeof(&arr) return?

字符串文字可以給你你用什麼上下文值或地址的依賴性。 。它例如嘗試:printf(" address: %p, value: %s", "Hello", "Hello");

  • 編譯器不驗證地址,但檢查語法

編譯器不負責驗證地址是否合法。編譯器移植代碼並檢查語法錯誤(例如不可編譯的類型不匹配)。假設你給一個指針指定了一個僞地址,它不會給你一個戰鬥(如果你輸入的是正確的地址)。考慮下面的例子:

例如-2:

#include<stdio.h> 
int main(int argc, char **argv){ 
    char* filename = "filename.txt"; 
    char* ptr = (char*)0x020202; 
    printf("%s %s\n", filename, ptr); 
    return 0; 
} 

編譯:

$ gcc y.c -Wall -pedantic 

,也不會產生任何誤差或韋林氏。因爲語法上所有都很好而且有效。
(而ptr分配了一個可能不存在的假地址)。

  • 無效的地址會導致不確定的行爲在運行時

嗯,其優良的編譯,其中ptr分配AA假地址例如-2代碼和編譯器不產生任何錯誤/警告,甚​​至用棍子檢查標誌選項:-Wall -pedantic

但是執行此代碼是錯誤的。它試圖在printf語句中訪問分配給ptr的內存地址,並且該程序將表現異常(在不同的執行實例中)。在C - 它的語言標準叫做:Undefined behavior

執行此代碼時OS(但不是編譯器)檢測到進程違反內存權限 - 無效訪問有效內存時出現:SIGSEGV並訪問無效地址時出現:SIGBUS。這可能會導致進程終止/崩潰,並出現一些分段錯誤和coredump

要了解並瞭解訪問非法內存時可能發生的情況,請閱讀:strcat() implementation works but causes a core dump at the end

+0

關於你的觀點:」因此你可以把字符串地址分配給char *「,但是我分配字符串而不是字符串地址。地址應該有& – Manzer

+0

@Manzer當你將''filename.txt''分配給'filename'時,你實際上是將字符串''filename.txt'的地址分配給指針。 –

+0

@Manzer在字符串位複雜的數據結構中,然後當你做'i = 4'或'c ='A''時,你需要'char','int',你正在賦值,但是當你做'char * ptr =「hello」'的時候,你正在分配地址, 'char str [] =「hello」;'你正在分配值 –

1
  1. 是的,它是持有一個地址,但它也恰好是地址後面是隔壁鄰居的地址,以及他們隔壁鄰居的地址等。通過這個「字符串」該值實際上找到的地址。
  2. 編譯器不應該產生錯誤,因爲它可能很有可能在將來某個時間點創建「filename.txt」文件,直到程序實際運行時纔會對fopen進行調用。
+0

我認爲地址和字符串是不同的,地址只能是固定的值,而字符串可以是任何東西,所以filename需要一個有效的物理地址,傳遞任何任意字符串。會你介意給一些更多的解釋?在此先感謝那 – Manzer

+0

@Manzer是的,它是持有一個地址,嘗試打印:'printf(「地址:%p,值:%s」,「你好」,「你好」);'一個字符串返回什麼你想要什麼。這取決於你想要的。 –

+0

@Manzer字符串可以是任何東西......在一系列連續的地址處。 – cwallenpoole

相關問題