討論區快速選單
知識庫快速選單
討論區最近新進100則主題 傑米的攝影旅遊筆記 網路投保旅行平安險
[ 回上頁 ] [ 討論區發言規則 ]
這些例子中,哪幾個屬於字串(字元陣列+\0) 哪幾個屬於純放字元的陣列?
更改我的閱讀文章字型大小
作者 : kotty123()
[ 貼文 56 | 人氣 0 | 評價 10 | 評價/貼文 0.18 | 送出評價 12 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/20 上午 12:56:15
char t[8] ="rtb\0yyk\0";

char t2[8] ="rtb\0abcd";

char t3[8] ="\0";

char t4[8] ="\0\0\0\0\0\0\0\0";

char t5[8] ="\0\0\0\0\0\0\0";

char t6[8] ="rtb\0";

char t7[8] ="r\0";

char t8[8] ="rtb\0yy";

char t9[8] ="\0yyk\0";

char t10[8] ="\0yyk";

我原本還有更多的例子要問
不過我覺得列出這樣就好,搞不好各位給我回覆後,我就瞭解了如何分辨

請問這10個陣列中,哪幾個是屬於 字串(字元陣列+\0) 還是 純粹放字元的陣列呢?



這些例子是我自己想的,當然也有先想過
但絞盡腦汁想不出來這些陣列是歸在哪一類

真的必須靠各位的協助



作者 : ice_emissary(燃燒的大地) 貼文超過200則
[ 貼文 409 | 人氣 0 | 評價 1890 | 評價/貼文 4.62 | 送出評價 18 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/20 上午 08:35:43
說實在的,你舉的例子只由一個而已,其他的東西都是一樣的!

其實C語言的字串與陣列並沒有不同,事實上C語言「語法」中並沒有字串這種東西。
任何字串一定是個陣列,而陣列不一定是個字串。字串其實就是陣列的一個特例:陣列元素以字元為主,並且最後一個有效元素為零。

以雙引號包裹的字面常數字串一定會幫你補個零結尾,不過當你把它存入指定長的陣列時,資料會被截斷、或補零補齊。
以下把你舉的例子解釋一下,看看你能不能比較容易明白?
我先把你的雙引號字串第一步改寫成字元陣列,然後第二步再依陣列長度8的要求將之縮減、或括增為最後存在tX陣列裡的資料。

char t[8] ="rtb\0yyk\0"; --> {'r','t','b',0,'y','y','k',0,0} --> {'r','t','b',0,'y','y','k',0}
char t2[8] ="rtb\0abcd"; --> {'r','t','b',0,'a','b','c','d',0} --> {'r','t','b',0,'a','b','c','d'}
char t3[8] ="\0"; --> {0,0} --> {0,0,0,0,0,0,0,0}
char t4[8] ="\0\0\0\0\0\0\0\0"; --> {0,0,0,0,0,0,0,0,0} --> {0,0,0,0,0,0,0,0}
char t5[8] ="\0\0\0\0\0\0\0"; --> {0,0,0,0,0,0,0,0} --> {0,0,0,0,0,0,0,0}
char t6[8] ="rtb\0"; --> {'r','t','b',0,0} --> {'r','t','b',0,0,0,0,0}
char t7[8] ="r\0"; --> {'r',0,0} --> {'r',0,0,0,0,0,0,0}
char t8[8] ="rtb\0yy"; --> {'r','t','b','0','y','y',0} --> {'r','t','b','0','y','y',0,0}
char t9[8] ="\0yyk\0"; --> {0,'y','y','k',0,0} --> {0,'y','y','k',0,0,0,0}
char t10[8] ="\0yyk"; --> {0,'y','y','k',0} --> {0,'y','y','k',0,0,0,0}

最後,你自己寫的 strcmp 函式寫好了嗎?可以拿出來討論了嗎?
作者 : ice_emissary(燃燒的大地) 貼文超過200則
[ 貼文 409 | 人氣 0 | 評價 1890 | 評價/貼文 4.62 | 送出評價 18 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/20 上午 08:42:59
你寫好 strcmp 之後比較一下下面這些字串對看看,然後看有什麼心得沒有?

"abcdefg"
"abcdefg"

"abcdefg"
"abcdefghijk"

"abcdefg"
"abcd"

"abcdefg"
"abc8efg"

"abcdefg"
"abc8efghijk"

你做完之後還可以做做 strncpy,strchr,我想如果這3個函式都做完的話,你一定會對字串更了解。
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/20 上午 10:07:15
在 C 語言裡, 根本沒有「字串」這個類型. 所謂的「字串」, 都是用「字元陣列」來模擬出來的. 「字串」只不過是個有特殊內容的「字元陣列」, 它唯一特殊的地方就是終結字元的存在. 只要有終結字元, 這個「字元陣列」就能夠當作「字串」來使用.

所以「字串」與否, 是以陣列的內容來做決定的. 只要陣列內容有終結字元, 它就可以當作字串來用, 就可以用在 str*() 等字串函式上. 標準字串函式根本不管陣列有多少個終結字元, 它們只以第一個找到的終結字元做為動作結束的依據. 如果陣列內容沒有終結字元, 它會一直搜尋下去, 一直到超出陣列範圍並導致不可預期的結果為止.
作者 : kotty123(存在)
[ 貼文 56 | 人氣 0 | 評價 10 | 評價/貼文 0.18 | 送出評價 12 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/20 下午 04:46:39

>說實在的,你舉的例子只由一個而已,其他的東西都是一樣的!
>
>其實C語言的字串與陣列並沒有不同,事實上C語言「語法」中並沒有字串這種東西。
>任何字串一定是個陣列,而陣列不一定是個字串。字串其實就是陣列的一個特例:陣列元素以字元為主,並且最後一個有效元素為零。
>.........
>.....


我把你的回覆看了好幾遍
但好像還是不太理解

以你的第一步驟 跟 第二步驟的範例
char t[8] ='rtb\0yyk\0'; --> {'r','t','b',0,'y','y','k',0,0} --> {'r','t','b',0,'y','y','k',0}

第一步驟我看到的是,就算陣列最後元素是空字元,但陣列還是會再補一個空字元,
但第二步驟因為我的陣列只有8個元素,所以最後面自動補的空字元無法存入,
也就是說我這個t陣列應該再留一個空位給空字元?








作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/21 上午 12:46:40
首先看字面字串 ("example") 在 C 及 C++ 語言裡的定義. 在 C++ 裡, 所有的字面字串都有一個隱藏的終結字元. "example" 總共佔了 8 個字元, 'e', 'x', 'a', 'm', 'p', 'l', 'e' 佔前 7 個, 第 8 個就是那個隱藏的終結字元 '\0'.

在 C 語言裡, 如果字面字串是用來初始化陣列的, 那終結字元只有在陣列有足夠空間時才會加入:
  char a1[] = "abc"; /* 等於 char a1[] = {'a', 'b', 'c', '\0'}; */

  char a2[3] = "abc"; /* 等於 char a2[] = {'a', 'b', 'c' };
              或 char a2[3] = {'a', 'b', 'c'}; */

  char a3[5] = "abc"; /* 等於 char a3[] = {'a', 'b', 'c', '\0', '\0'}
              或 char a3[5] = {'a', 'b', 'c', '\0' }; */

  char a4[3] = "abcde"; /* 等於 char a4[3] = {'a', 'b', 'c', 'd', 'e', '\0'}; */

第一個 a1 用的是 [], 它告訴編譯器陣列的長度由初始值來決定. 不管 C 還是 C++, 隱藏的終結字元是初始值的一部分.

第二個 (a2) 句子只能在 C 編譯器上編譯. 這個句子在 C++ 是錯誤的. 因為在 C++, "abc" 永遠都佔 4 個位元, 初始資料的長度不能大過陣列大小.

第三個 (a3) 句子可以在 C 或 C++ 編譯器上編譯. 如果初始資料的長度小於陣列大小, 編譯器會自動的把剩餘的陣列元素用 0 來填補. 這個句子的註解裡, 'c' 後面的 '\0' 是初始值 "abc" 的隱藏終結字元. 如果用 char a3[] = {...} 的寫法, {} 內必須寫出陣列大小所需的所有初始值. 因為原來的 a3 有 5 個元素, 所以註解裡的第一個寫法要補多一個 '\0'. 第二個寫法不用補 '\0', 因為已寫明陣列大小, 編譯器會自動的補 0.

第四個 (a4) 句子不管在 C 或 C++ 都是編譯錯誤. 因為初始值超出陣列大小.


>char t[8] ="rtb\0yyk\0";

等於 char t[8] = { 'r', 't', 'b', '\0', 'y', 'y', 'k', '\0' };

>char t2[8] ="rtb\0abcd";

等於 char t2[8] = { 'r', 't', 'b', '\0', 'a', 'b', 'c', 'd' };

上面這兩句在 C 語言這是允許的, 在 C++ 則是錯誤. 因為在 C++ 的定義下, 所有字面字串都有一個隱藏的終結字元, "rtb\0yyk\0" 及 "rtb\0abcd" 都佔 9 個字元.

至於它們是不是 C 語言的字串, 要看你從那個位址看.
  從 t 或是 &t[0] 來看, 它是 "rtb".
  從 &t[1] 來看, 它是 "tb".
  從 &t[2] 來看, 它是 "b".
  從 &t[3] 來看, 它是 "" (空字串).
  從 &t[4] 來看, 它是 "yyk".
  從 &t[5] 來看, 它是 "yk".
  從 &t[6] 來看, 它是 "k".
  從 &t[7] 來看, 它是 "" (空字串).

至於 t2:
  從 t2 或是 &t2[0] 來看, 它是 "rtb".
  從 &t2[1] 來看, 它是 "tb".
  從 &t2[2] 來看, 它是 "b".
  從 &t2[3] 來看, 它是 "" (空字串).
  從 &t2[4] 來看, 一直到陣列的最後一個元素都沒有終結字元, 所以從這個位址開始, 你不能把它當作字串來用, 只能是字元陣列.

>char t3[8] ="\0";

等於 char t3[8] = { '\0', '\0' };

第一個 '\0' 是字面字串 "\0" 的第一個字元; 第二個 '\0' 是字面字串裡隱藏的終結字元. 跟這個比較:
  char x[8] = "";
它等於:
  char x[8] = { '\0' };

因為空字串並不真的是空的, 它還有一個隱藏的終結字元.

在這個例子裡, 由於初始資料少於陣列大小, 編譯器會自動的補 0. 事實上, 這是把整個陣列零化最方便的一個作法:
  int array[100] = { 0 };
  char buffer1[1024] = { 0 };
  char buffer2[1024] = "";

>char t4[8] ="\0\0\0\0\0\0\0\0";

這個句子對 C++ 來說是錯誤的. 在 C 語言的定義下, 這個句子等於:
  char t4[8] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
上面的 '\0' 都是字面字串裡明寫出來的初始字元, 不包括隱藏的終結字元.


>char t5[8] ="0\0\0\0\0\0\0";

這個就可以在 C++ 上編譯了. 它等於:
  char t5[8] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };

看起來跟上面的 t4 一樣, 但這裡的最後一個 '\0' 是屬於隱藏的終結字元. 前 7 個 '\0' 才是明寫出來的初始字元.


>char t6[8] ="rtb\0";

等於 char t6[8] = { 'r', 't', 'b', '\0', '\0' };

第一個 '\0' 是初始字串內的第 4 個字元; 第二個 '\0' 是終結字元.


>char t7[8] ="r\0";

等於 char t7[8] = { 'r', '\0', '\0' };


>char t8[8] ="rtb\0yy";

等於 char t8[8] = { 'r', 't', 'b', '\0', 'y', 'y', '\0' };


>char t9[8] ="\0yyk\0";

等於 char t9[8] = { '\0', 'y', 'y', 'k', '\0', '\0' };


>char t10[8] ="\0yyk";

等於 char t10[8] = { '\0', 'y', 'y', 'k', '\0' };


上面從 t6 開始, 最後一個 '\0' 都是隱藏的終結字元. 在終結字元之前的都是初始字串裡的初始字元. 如果初始資料 (明寫的初始字元 + 隱藏的終結字元) 少過陣列大小, 編譯器會在終結字元後補 0.

作者 : ice_emissary(燃燒的大地) 貼文超過200則
[ 貼文 409 | 人氣 0 | 評價 1890 | 評價/貼文 4.62 | 送出評價 18 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/21 上午 09:10:41
> 第四個 (a4) 句子不管在 C 或 C++ 都是編譯錯誤. 因為初始值超出陣列大小.

可我記得這種狀況是可以的,過長的部份會被截斷就是。
我剛剛試了一下,C++ 不行但 C 可以編譯通過,會有警告就是。
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/21 上午 10:16:17
>> 第四個 (a4) 句子不管在 C 或 C++ 都是編譯錯誤. 因為初始值超出陣列大小.
>
>可我記得這種狀況是可以的,過長的部份會被截斷就是。
>我剛剛試了一下,C++ 不行但 C 可以編譯通過,會有警告就是。

剛剛再看了一下 C99 標準文件. 在 6.7.8 Initialization 裡, 第 14 段:
An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialized the elements of the array.

所以 C 語言是允許初始字面字串長過字元陣列的大小的, 這也許有歷史上的原因. 但無論如何, 上面所有的例子是可以在 C 編譯器上編譯的. 但因為過長的部份會被截斷, 所以字元陣列也許不會有終結字元, 除非在截斷之前的初始化字元裡面本身有 0 值的字元, 這個 0 值的字元就可被當作終結字元.

如果陣列內容沒有終結字元, 陣列就不能當作 C-字串來用. 很多的標準字串函式如 strcmp() 是不能用的, 但有些可以用, 如 strncmp(), 這些函式多了一個「長度」的參數.

再另外看了看 C++ 的標準文件, 在 8.5.2 Character arrays 裡, 第 2 段:
There shall not be more initializers than there are array elements. [ Example:
char cv[4] = "asdf"; // error
is ill-formed since there is no space for the implied trailing ’\0’. —end example ]

所以之前的回覆請自己修改修改.

再補充一些題外話, 在視窗系統上, 有些 API 會需要一種特殊內容的字串, 它特殊的地方在於可以儲存多筆資料, 每一筆資料是以 0 值字元來分割的, 最後一筆資料用兩個 0 值字元來標示. (http://blogs.msdn.com/b/oldnewthing/archive/2009/10/08/9904646.aspx)
作者 : kotty123(存在)
[ 貼文 56 | 人氣 0 | 評價 10 | 評價/貼文 0.18 | 送出評價 12 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/23 下午 02:49:20
抱歉各位
我把我想要問的問題
抄在紙上,
但電腦壞了,用手機打字的效率很差又時常打錯
所以我可能會晚幾天才問


作者 : kotty123(存在)
[ 貼文 56 | 人氣 0 | 評價 10 | 評價/貼文 0.18 | 送出評價 12 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/31 下午 05:09:54
這是對於
Raymond 詳細解說的第一問題


1.
char t[8]="rtb\0yyk\0";
以c語言角度看, t陣列裡有兩個字串,
但這整個t陣列仍不是一個字串(字元陣列),因為最後面還需要1個空字元,
而元素7雖是空字元, 但這空字元是屬於yyk的,
真正要決定整個字元陣列是不是字串,必須是編譯器自動在最後面補上的空字元,
而不是自己寫上的

而像你提到的 char a1[]="abc";
假如改寫成 char a1[]="abc\0";
那a仍是純粹放字元的陣列,不是字串,
要等編譯後自動在後面補空字元,a1才算是字串


以上是我吸收到的,請問有哪裡錯誤?
謝謝
作者 : ice_emissary(燃燒的大地) 貼文超過200則
[ 貼文 409 | 人氣 0 | 評價 1890 | 評價/貼文 4.62 | 送出評價 18 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/31 下午 05:33:02
簡單的回答你:你的理解不太對!
先不要糾結太多在字串不字串上面,反正所有的東西都是陣列就對了。

還有,你的 strcmp, strncpy, strchr, strstr 寫好了沒?
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/8/31 下午 09:23:02
>在 char t[8]="rtb\0yyk\0";
>以c語言角度看, t陣列裡有兩個字串,

錯! 如果你把 t 傳入任何一個字串處理函式裡, 它們只會進行到第一個 '\0':
  printf("%s\n", t); /* 會輸出前三個字元 'r', 't', 'b' */
  size_t n = strlen(t); /* 會傳回 3 */
  strcat(t, "??"); /* t 的內容會變成 { 'r', 't', 'b', '?', '?', '\0', 'k', '\0' } */

所有的標準字串函式都不會去管第一個 '\0' 後面的內容, 標準函式是 C 語言定義的一部份, 也就是說, 從 C 語言角度看, t 陣列只有一個字串.

C 語言標準只有一種字串, 就是: nul-terminated string. 在我 8/21 的回覆裡, 最後提到了一種特殊內容的字串, 這種字串叫做 nul-separated string, 它用 '\0' 來分隔多筆字串資料, 最後一筆資料後用兩個 '\0' 來做整組資料的終結. 從這個角度來看, 這裡的 t 也不是一個合格的資料格式.


>但這整個t陣列仍不是一個字串(字元陣列),因為最後面還需要1個空字元,
>而元素7雖是空字元, 但這空字元是屬於yyk的,
>真正要決定整個字元陣列是不是字串,必須是編譯器自動在最後面補上的空字元,
>而不是自己寫上的

完全錯誤的理解! 決定字元陣列是不是字串的是: _字_元_陣_列_的_內_容_. 不管這個內容是在什麼時候, 由誰填入的. 只要有終結字元, 它就是 C 語言定義下的字串, 至於終結字元後面的內容是根本不管的.


>而像你提到的 char a1[]="abc";
>假如改寫成 char a1[]="abc\0";
>那a仍是純粹放字元的陣列,不是字串,
>要等編譯後自動在後面補空字元,a1才算是字串

請問對標準字串函式來說, 這兩個 a1 有分別嗎? 這兩個不同寫法的 a1, 它們唯一的分別只是陣列的長度, 第一個佔 4 個字元: {'a', 'b', 'c', '\0'}, 第二個佔 5 個字元: {'a', 'b', 'c', '\0', '\0' }.

你認為第一個 {'a', 'b', 'c', '\0' } 不是字串嗎!? 那請問 C-字串 的定義是什麼? C-字串的定義就是一個有終結字元的字元陣列. 從這個定義來看, 它跟 { 'a', 'b', 'c', '\0', '\0' } 有什麼不同. 只要有終結字元就是 C-字串, 誰管這個終結字元是怎麼來的!!!


>以上是我吸收到的,請問有哪裡錯誤?

你的錯誤就是你把一個很簡單的東西想得太複雜, 把一個很簡單的定義自作聰明的加了沒有必要的限制跟條框.
作者 : kotty123(存在)
[ 貼文 56 | 人氣 0 | 評價 10 | 評價/貼文 0.18 | 送出評價 12 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/1 下午 11:47:27
>錯! 如果你把 t 傳入任何一個字串處理函式裡, 它們只會進行到第一個 '\0':
>  printf('%s
', t); /* 會輸出前三個字元 'r', 't', 'b' */
>  size_t n = strlen(t); /* 會傳回 3 */
>  strcat(t, '??'); /* t 的內容會變成 { 'r', 't', 'b', '?', '?', '\0', 'k', '\0' } */
>
>所有的標準字串函式都不會去管第一個 '\0' 後面的內容, 標準函式是 C 語言定義的一部份, 也就是說, 從 C 語言角度看, t 陣列只有一個字串.
>
>C 語言標準只有一種字串, 就是: nul-terminated string. 在我 8/21 的回覆裡, 最後提到了一種特殊內容的字串, 這種字串叫做 nul-separated string, 它用 '\0' 來分隔多筆字串資料, 最後一筆資料後用兩個 '\0' 來做整組資料的終結. 從這個角度來看, 這裡的 t 也不是一個合格的資料格式.



這個我有測試過,我知道有關字串的處理函式是只會讀到第1個字串,
但這個陣列的第二個字串是確實存在記憶體, 不是函式沒讀到就不存在
而就是因為它存在
所以我才有疑問

而你說的nul-separated string, 分隔多筆字串資料的陣列,
最後一筆字串後用兩個\0做整筆資料的結束,
請問為什麼要用兩個\0 ?
那編譯器還會在補一個\0嗎?

很抱歉,因為我所吸收的完全不對,變成我要從頭開始問了





>完全錯誤的理解! 決定字元陣列是不是字串的是: _字_元_陣_列_的_內_容_. 不管這個內容是在什麼時候, 由誰填入的. 只要有終結字元, 它就是 C 語言定義下的字串, 至於終結字元後面的內容是根本不管的.

>
>請問對標準字串函式來說, 這兩個 a1 有分別嗎? 這兩個不同寫法的 a1, 它們唯一的分別只是陣列的長度, 第一個佔 4 個字元: {'a', 'b', 'c', '\0'}, 第二個佔 5 個字元: {'a', 'b', 'c', '\0', '\0' }.
>
>你認為第一個 {'a', 'b', 'c', '\0' } 不是字串嗎!? 那請問 C-字串 的定義是什麼? C-字串的定義就是一個有終結字元的字元陣列. 從這個定義來看, 它跟 { 'a', 'b', 'c', '\0', '\0' } 有什麼不同. 只要有終結字元就是 C-字串, 誰管這個終結字元是怎麼來的!!!




為甚麼第二個寫法會多出一個\0
就算自己在陣列最後補上\0,編譯器仍會自動補\0 嗎?






>
>
>>以上是我吸收到的,請問有哪裡錯誤?
>
>你的錯誤就是你把一個很簡單的東西想得太複雜, 把一個很簡單的定義自作聰明的加了沒有必要的限制跟條框.

你撥空回覆我,我很感激,因為你也有你自己的事要做
但我不是自作聰明,我同樣也很努力的在分析,我還寫了很多紙條,
為了讓你知道我吸收的情況,我也盡量用例子或更好的表示法,
雖說我吸收的完全錯誤

而可能是因為吸收的全錯,
我到現在還不覺得這是很簡單的東西 ...
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/2 下午 10:04:58
>這個我有測試過,我知道有關字串的處理函式是只會讀到第1個字串,
>但這個陣列的第二個字串是確實存在記憶體, 不是函式沒讀到就不存在

不是這樣子的, 這不是哲學上的問題, 程式語言對各種物件有嚴謹的定義. C 語言只支援一種字串, 就是 nul-terminated character array. 這是 C 語言的定義. 在這個定義下, 字串的定義只到第一個終結字元為止.

從 C 語言的角度來看, char t[8]="rtb\0yyk\0" 只有一個字串.

nul-separated string 是程式員根據程式邏輯需要自行定義的一種資料架構, 這個不在 C 語言的字串定義裡. 這是程式員在 C 語言字串定義的基礎上展延出來的, 新的字串架構定義, 程式員必須自己寫函式來讀取這些特殊資料.


>而就是因為它存在
>所以我才有疑問

基本架構是字元陣列, 這是 C 語言的基本架構. C 語言沒有「字串」類型, 「字串」在 C 語言裡是定義為 0 終結字元的字元陣列. 「字串」是「字元陣列」的subset, 所有的字串都是字元陣列, 但只有 0 作為終結字元的字元陣列才能當作字串來用.

你可以在字元陣列, 或 C-字串的基礎上定義你自己想要的字串架構. 其中一個產物就是以 0 作為分隔字元的字串組, 也就是上面提到的 nul-separated string. 這個字串組架構有個基本的缺陷 - 它無法表示「空字串」. 但這個不是大問題, 因為在使用這個 nul-separated string 的 API 是沒有「空字元」的.

你可以根據你程式的需要定義特殊內容的字元陣列, 你可以說: "ab\0xyz\0" 有兩個字串, 以 0 來分隔 這是你自己的定義, 你自己的 API. 並寫特別的支援函式來存取其內容. 但這不是 C 語言字串的定義, 對 C 語言來說, 從第一個字元開始到第一個終結字元就是整個字串.


>而你說的nul-separated string, 分隔多筆字串資料的陣列,
>最後一筆字串後用兩個\0做整筆資料的結束,
>請問為什麼要用兩個\0 ?

因為每一筆資料都用 0 來分隔, 在不知道有多少筆資料及陣列長度的情況下, 你要如何知道資料何時結束?

自己寫個函式來讀取 nul-separated string 就明白了.


>那編譯器還會在補一個\0嗎?
>很抱歉,因為我所吸收的完全不對,變成我要從頭開始問了

你不要總想成是編譯器補 0. 在 C 及 C++ 語言裡, 所有的字面字串都有一個隱藏的終結字元. "abcd" 佔 5 個字元, 第五個字元是終結字元. 字串的終結字元是 C 語言裡唯一隱藏起來的, 多出來的資料. C++ 隱藏的資料比 C 多.

這個隱藏的終結字元永遠存在. 問題在於, C 語言允許初始化的資料超出陣列長度, 當這個情形出現時, 編譯器只會初始化到陣列長度, 這就導致了陣列裡的資料有可能沒有終結字元. 這是 C 語言的一個「特性」, 也是它跟 C++ 語言諸多不相容之一. C++ 語言不允許陣列長度小於初始資料的數量, 所以用字面字串來初始陣列, 陣列一定有終結字元.


>為甚麼第二個寫法會多出一個\0
>就算自己在陣列最後補上\0,編譯器仍會自動補\0 嗎?

隱藏的終結字元是字面字串的一部份, 這是 C 及 C++ 程式語言的定義. 字面字串的終結字元永遠存在, 跟字面字串的內容完全沒有關係. "\0\0\0\0" 也佔 5 個字元. 既然終結字元是字面字串的一部份, 哪裡有「補」的說法!


>你撥空回覆我,我很感激,因為你也有你自己的事要做
>但我不是自作聰明,我同樣也很努力的在分析,我還寫了很多紙條,
>為了讓你知道我吸收的情況,我也盡量用例子或更好的表示法,
>雖說我吸收的完全錯誤

說你自作聰明沒有貶低你或責怪或取笑的意思. 我的意思就是你把它想得太過複雜. 相對 C 語言裡的其它概念, 「字串」在 C 語言裡算是簡單的: 就是一個有終結字元的字元陣列, 終結字元即認定為字串的結束. 任何字面字串必有一個隱藏起來的終結字元, 跟字串的內容沒有關係. C 字串從第一個字元開始, 一直到終結字元為止. 特殊格式的字串格式必須自行處理.
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1043 | 人氣 3227 | 評價 1270 | 評價/貼文 1.22 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/3 上午 02:48:56
#include "stdio.h"
int main()
{
  // 對 C 來說 "abc" 就是字串,用 const char[4] 的空間來存放
  // 所以 "rtb\0yyk\0" 佔用 const char[9] 的空間,會自動在最後再多放個 '\0'
  // 但是,C 雖然將 "abc" 視為字串,也要看處理它的函數是不是將它視為字串才行
  // 比如 printf()、strlen() ...等等
  // 以下看看處理字串的 printf() 會造成怎樣的結果,

  char a1[] = "abc"; // 拷貝了 4 個 char 給 a1
  char a2[4] = "abc"; // 拷貝了 4 個 char 給 a2
  char a3[3] = "abc"; // 拷貝了 3 個 char 給 a3

  printf("a1 = %s \n", a1);
  printf("a2 = %s \n", a2);
  printf("a3 = %s \n", a3);

  return 0;
}

輸出結果:
a1 = abc
a2 = abc
a3 = abc昍昍昍昍岬bc

這都是因為要那個 '\0' 所造成的後果

C++ 有一個 std::string 的物件,不再用 '\0' 視為字串的結尾,且有效控管空間
作者 : kotty123(存在)
[ 貼文 56 | 人氣 0 | 評價 10 | 評價/貼文 0.18 | 送出評價 12 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/5 上午 02:32:25
>不是這樣子的, 這不是哲學上的問題, 程式語言對各種物件有嚴謹的定義. C 語言只支援一種字串, 就是 nul-terminated character array. 這是 C 語言的定義. 在這個定義下, 字串的定義只到第一個終結字元為止.
>從 C 語言的角度來看, char t[8]='rtb\0yyk\0' 只有一個字串.
>nul-separated string 是程式員根據程式邏輯需要自行定義的一種資料架構, 這個不在 C 語言的字串定義裡. 這是程式員在 C 語言字串定義的基礎上展延出來的, 新的字串架構定義, 程式員必須自己寫函式來讀取這些特殊資料.
>
>基本架構是字元陣列, 這是 C 語言的基本架構. C 語言沒有「字串」類型, 「字串」在 C 語言裡是定義為 0 終結字元的字元陣列. 「字串」是「字元陣列」的subset, 所有的字串都是字元陣列, 但只有 0 作為終結字元的字元陣列才能當作字串來用.
>
>你可以在字元陣列, 或 C-字串的基礎上定義你自己想要的字串架構. 其中一個產物就是以 0 作為分隔字元的字串組, 也就是上面提到的 nul-separated string. 這個字串組架構有個基本的缺陷 - 它無法表示「空字串」. 但這個不是大問題, 因為在使用這個 nul-separated string 的 API 是沒有「空字元」的.







"這個字串組架構有個基本的缺陷 - 它無法表示「空字串」"
所謂的空字串是指像 char y[]=""; 嗎?


還有
" nul-separated string 的 API 是沒有「空字元」的 "
這不清楚其意思,為甚麼沒有空字元







>
>你可以根據你程式的需要定義特殊內容的字元陣列, 你可以說: 'ab\0xyz\0' 有兩個字串, 以 0 來分隔 這是你自己的定義, 你自己的 API. 並寫特別的支援函式來存取其內容. 但這不是 C 語言字串的定義, 對 C 語言來說, 從第一個字元開始到第一個終結字元就是整個字串.









" 這是你自己的定義, 你自己的 API "

我已經google過API的意思了,每個文章所說的API都有點不同
但想確定一下,
API 就是 對某語言或某定義所寫的函式庫

這樣說對嗎? 還是有什麼需要修正的地方?









>
>因為每一筆資料都用 0 來分隔, 在不知道有多少筆資料及陣列長度的情況下, 你要如何知道資料何時結束?
>自己寫個函式來讀取 nul-separated string 就明白了.





假如
char h1[]="abc\0def\0";

char h2[9]="abc\0def\0"

這樣h1跟2的初值後面不是還有個隱藏字元,那這樣就等於後面有兩個\0
應該不需要在後面自己補兩個0不是嗎?










>你不要總想成是編譯器補 0. 在 C 及 C++ 語言裡, 所有的字面字串都有一個隱藏的終結字元. 'abcd' 佔 5 個字元, 第五個字元是終結字元. 字串的終結字元是 C 語言裡唯一隱藏起來的, 多出來的資料. C++ 隱藏的資料比 C 多.





也就是說 假如像 char a[]="abc";
在c語言 , abc這字面字串本身就是占4個字元, 並不是編譯器自己在abc後補0 ?






>這個隱藏的終結字元永遠存在. 問題在於, C 語言允許初始化的資料超出陣列長度, 當這個情形出現時, 編譯器只會初始化到陣列長度, 這就導致了陣列裡的資料有可能沒有終結字元. 這是 C 語言的一個「特性」, 也是它跟 C++ 語言諸多不相容之一. C++ 語言不允許陣列長度小於初始資料的數量, 所以用字面字串來初始陣列, 陣列一定有終結字元.






也就是在C語言 , 假如初始化資料數量超出陣列本身長度,
編譯器不會把終結字元算在陣列長度裡,它只會把初始化資料的數量等於陣列長度
是這樣嗎?







>
>隱藏的終結字元是字面字串的一部份, 這是 C 及 C++ 程式語言的定義. 字面字串的終結字元永遠存在, 跟字面字串的內容完全沒有關係. '\0\0\0\0' 也佔 5 個字元. 既然終結字元是字面字串的一部份, 哪裡有「補」的說法!





補結束字元的情況,是不是終結字元前面的資料 + 終結字元本身,
數量仍不及陣列長度才在終結字元後補0至符合陣列長度?





>說你自作聰明沒有貶低你或責怪或取笑的意思. 我的意思就是你把它想得太過複雜. 相對 C 語言裡的其它概念, 「字串」在 C 語言裡算是簡單的: 就是一個有終結字元的字元陣列, 終結字元即認定為字串的結束. 任何字面字串必有一個隱藏起來的終結字元, 跟字串的內容沒有關係. C 字串從第一個字元開始, 一直到終結字元為止. 特殊格式的字串格式必須自行處理.
 


好的, 非常抱歉誤會你的意思
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/5 下午 08:35:57
>"這個字串組架構有個基本的缺陷 - 它無法表示「空字串」"
>所謂的空字串是指像 char y[]=""; 嗎?

是的.


>還有
>" nul-separated string 的 API 是沒有「空字元」的 "
>這不清楚其意思,為甚麼沒有空字元

打錯了, 應該是 「空字串」. 至於原因, 應該不難想到.


>我已經google過API的意思了,每個文章所說的API都有點不同
>但想確定一下,
>API 就是 對某語言或某定義所寫的函式庫
>這樣說對嗎? 還是有什麼需要修正的地方?

http://stackoverflow.com/questions/3678665/is-there-still-a-difference-between-a-library-and-an-api

http://stackoverflow.com/questions/3678665/is-there-still-a-difference-between-a-library-and-an-api

https://en.wikipedia.org/wiki/Application_programming_interface

>假如
>char h1[]="abc\0def\0";
>
>char h2[9]="abc\0def\0"
>
>這樣h1跟2的初值後面不是還有個隱藏字元,那這樣就等於後面有兩個\0

是的, 沒錯.

>應該不需要在後面自己補兩個0不是嗎?

你認為你自己定義的特殊字串需要多少個 0 就自己在裡面加, 不管你原字串在後面有多少個 0, 初始字元最後一定會多出一個終結字元.

如果是以視窗 API 用的 nul-separated string 來看, 上面寫的就可以了.

上面的式子跟這個是一樣的:
  char h1[] = { 'a', 'b', 'c', 0, 'd', 'e', 'f', 0, 0 };
  char h2[9] = { 'a', 'b', 'c', 0, 'd', 'e', 'f', 0, 0 }

這樣會不會比較容易明白一點.


>也就是說 假如像 char a[]="abc";
>在c語言 , abc這字面字串本身就是占4個字元, 並不是編譯器自己在abc後補0 ?

是的. 這樣想是不是很簡單!?


>也就是在C語言 , 假如初始化資料數量超出陣列本身長度,
>編譯器不會把終結字元算在陣列長度裡,它只會把初始化資料的數量等於陣列長度
>是這樣嗎?

再看了一下 C 語言標準說明, 在 C99 6.7.8 Initialization 第二段:

No initializer shall attempt to provide a value for an object not contained within the entity being initialized.

同樣的敘述也在 C11 6.7.9 Initialization 的第二段.

所以 C 語言也是不允許初始化資料超出陣列長度的. 這點跟 C++ 是一樣的.

但 C 語言標準允許一個例外, 就是當你用字面字串來初始化字元陣列的時候, 如果字元陣列的長度剛好不足以放入字面字串的終結字元 (就是那個所有的字面字串都有的, 隱藏起來的終結字元), 那這個終結字元會悄悄的被捨棄掉.

所以在 C 語言裡, 陣列的大小至少必須等於初始字面字串的長度. 如果陣列大小剛好等於初始字面字串的長度, 字面字串的終結字元就會被捨棄. 字元陣列的內容能否當作字串來用, 就要看初始字面字串本身有沒有終結字元.

如果陣列長度大於初始值的數量, 編譯器會把陣列後面的內容初始化為 0 (這個才是真正的「補 0」). 這是陣列初始化的標準做法, 適用於任何類型的陣列, 包括架構. 比方說:
  char s[10] = { 'x' }; /* s[0] 初始化為 'x', s[1]~s[9] 「補0」*/
  int ia[10] = { 123 }; /* ia[0] 初始化為 123, ia[1]~ia[9] 「補0」*/

下面的例子裡, 我用 '\0' 來代表字面字串裡那個隱藏起來的終結字元. 用 0 來代表「補0」.

C++ 比 C 更多限制, C++ 連字面字串的終結字元 (就是那個所有的字面字串都有的, 隱藏起來的終結字元) 都不允許被捨棄.

  char a1[5] = "abc"; /* C OK, C++ OK */

a1 內容是 {'a', 'b', 'c', '\0', 0, }

  char a2[5] = "abcd"; /* C OK, C++ OK */
a2 內容是 { 'a', 'b', 'c', 'd', '\0' }

  char a3[5] = "abcde"; /* C OK, C++ 錯誤 */
在 C 語言下, a3 內容是 { 'a', 'b', 'c', 'd', 'e' }

  char a4[5] = "abcdef"; /* C 錯誤, C++ 錯誤 */


有些 C 編譯器 (如 gcc) 的預設更為寬鬆, 允許 a4 能夠被編譯, 嚴格來說這是不符標準的.

因為我個人不用 C, C 語言的這個特性對我來說沒有意義, 也很少去關注標準文件裡這方面的東西.


>補結束字元的情況,是不是終結字元前面的資料 + 終結字元本身,
>數量仍不及陣列長度才在終結字元後補0至符合陣列長度?

你可以看成是「補 0」, 真正的字眼是 zero initialized, 適用於任何類型, 包括指標, 架構. 編譯器會依據類型把它們設為 0 值. 在 C 及 C++ 標準裡都有關於 zero initialization 應該如何運作的說明.
作者 : kotty123(存在)
[ 貼文 56 | 人氣 0 | 評價 10 | 評價/貼文 0.18 | 送出評價 12 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/6 上午 12:45:20
>你認為你自己定義的特殊字串需要多少個 0 就自己在裡面加, 不管你原字串在後面有多少個 0, 初始字元最後一定會多出一個終結字元.
>如果是以視窗 API 用的 nul-separated string 來看, 上面寫的就可以了.




你8/21回覆最後面所提到的特殊定義字串在後面補2個\0, 讓我想挺久的

假如你說的例子的陣列是像
char m1[]="abc\0def\0ghi\0\0";
那這樣m1陣列最後面的空字元總共有3個,包括隱藏的空字元

而假如你說的例子的陣列是像
char m2[13]="abc\0def\0ghi\0\0";
那最後面的空字元就只有兩個
這樣說有對嗎?



我覺得你當時所說的特殊定義字串應該是像m2,是嗎?









>再看了一下 C 語言標準說明, 在 C99 6.7.8 Initialization 第二段:
>No initializer shall attempt to provide a value for an object not contained within the entity being initialized.
>同樣的敘述也在 C11 6.7.9 Initialization 的第二段.
所以 C 語言也是不允許初始化資料超出陣列長度的. 這點跟 C++ 是一樣的.
>但 C 語言標準允許一個例外, 就是當你用字面字串來初始化字元陣列的時候, 如果字元陣列的長度剛好不足以放入字面字串的終結字元 (就是那個所有的字面字串都有的, 隱藏起來的終結字元), 那這個終結字元會悄悄的被捨棄掉.
>所以在 C 語言裡, 陣列的大小至少必須等於初始字面字串的長度. 如果陣列大小剛好等於初始字面字串的長度, 字面字串的終結字元就會被捨棄. 字元陣列的內容能否當作字串來用, 就要看初始字面字串本身有沒有終結字元.



也就是假如像是
char u[5]="abcdefg";
陣列元素只有存到 'e' 而已
'f'跟'g'並沒存到,而終結字元當然也沒有存到,
這樣說有對嗎?











>如果陣列長度大於初始值的數量, 編譯器會把陣列後面的內容初始化為 0 (這個才是真正的「補 0」). 這是陣列初始化的標準做法, 適用於任何類型的陣列, 包括架構. 比方說:
>  char s[10] = { 'x' }; /* s[0] 初始化為 'x', s[1]~s[9] 「補0」*/



補0應該是從s[2]~s[9] 才對吧?
s[1]是終結字元








>int ia[10] = { 123 }; /* ia[0] 初始化為 123, ia[1]~ia[9] 「補0」*/


可能最近一直探討c字串的問題
害我看到123 僅是一個元素的值嚇到...

想確定一下
字元陣列的一個元素是不是不能塞好幾個字元?





作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/6 上午 10:21:14
>你8/21回覆最後面所提到的特殊定義字串在後面補2個\0, 讓我想挺久的

你指的是:
  『再補充一些題外話, 在視窗系統上, 有些 API 會需要一種特殊內容的字串, 它特殊的地方在於可以儲存多筆資料, 每一筆資料是以 0 值字元來分割的, 最後一筆資料用兩個 0 值字元來標示.』

請注意看, 我說的是『最後一筆資料用兩個 0 值字元來標示』, 並不是『在後面補2個\0』.

如果有兩筆資料: 「abc」跟 「xyz」, 用 nul-separated string 的格式來存放的話, 資料內容將會是:
  'a', 'b', 'c', 0, 'x', 'y', 'z', 0, 0

這裡的 0 不是終結字元, 是當作分隔字元. 資料本身是 { 'a', 'b', 'c' } 及 { 'x', 'y', 'z' }; 0 是一個特殊符號, 用來分隔資料. 最後一筆資料 { 'x', 'y', 'z' } 後面要兩個 0 來標示 end of data.

不知道你怎麼會牽涉到「補 0」.

因為這個格式

  char data[] = { 'a', 'b', 'c', 0, 'x', 'y', 'z', 0, 0 };

不方便寫, 也不好讀, 所以一般會用程式語言提供的方便寫法, 既字面字串:
  char data[] = "???";
所以問題是: 在考慮了 C 或 C++ 語言裡字面字串的定義後, ??? 要怎麼寫才能夠把 data 初始化成我們要的內容?

  char data[] = "abc\0xyz\0";



>假如你說的例子的陣列是像
>char m1[]="abc\0def\0ghi\0\0";
>那這樣m1陣列最後面的空字元總共有3個,包括隱藏的空字元
>
>而假如你說的例子的陣列是像
>char m2[13]="abc\0def\0ghi\0\0";
>那最後面的空字元就只有兩個
>這樣說有對嗎?
>
>我覺得你當時所說的特殊定義字串應該是像m2,是嗎?

不是! 我上面說的『特殊內容字串』, 用的例子是 nul-separated string. 特殊的地方不是字串後面有多少個 0, 特殊的地方是要怎麼把多筆資料放在一個字元陣列裡. 一般多筆資料是用指標陣列來儲存:
      +----+
  data| *--+--> "abc"
      |----|
      | *--+--> "def"
      |----|
      | *--+--> "ghi"
      |----|
      |NULL|
      +----+

但基於各種原因現在不想用指標陣列來做, 想要把所有資料放在一個字元陣列裡送出去. 你必須在原有資料內加入額外的訊息, 這樣才能知道每一筆資料在哪裡結束, 下一筆資料從哪裡開始, 整個資料何時結束. 方法有很多, 用 0 來分隔資料是其中一個方法.

>>再看了一下 C 語言標準說明, 在 C99 6.7.8 Initialization 第二段:
>>No initializer shall attempt to provide a value for an object not contained within the entity being initialized.
>>同樣的敘述也在 C11 6.7.9 Initialization 的第二段.
>所以 C 語言也是不允許初始化資料超出陣列長度的. 這點跟 C++ 是一樣的.
>>但 C 語言標準允許一個例外, 就是當你用字面字串來初始化字元陣列的時候, 如果字元陣列的長度剛好不足以放入字面字串的終結字元 (就是那個所有的字面字串都有的, 隱藏起來的終結字元), 那這個終結字元會悄悄的被捨棄掉.
>>所以在 C 語言裡, 陣列的大小至少必須等於初始字面字串的長度. 如果陣列大小剛好等於初始字面字串的長度, 字面字串的終結字元就會被捨棄. 字元陣列的內容能否當作字串來用, 就要看初始字面字串本身有沒有終結字元.
>
>
>也就是假如像是
>char u[5]="abcdefg";
>陣列元素只有存到 "e" 而已
>"f"跟"g"並沒存到,而終結字元當然也沒有存到,
>這樣說有對嗎?

你完全沒有看懂我上面所說的對嗎? 如果你有看懂的話, 你就知道
  char u[5] = "abcdefg";
因該是編譯錯誤!!!

>>如果陣列長度大於初始值的數量, 編譯器會把陣列後面的內容初始化為 0 (這個才是真正的「補 0」). 這是陣列初始化的標準做法, 適用於任何類型的陣列, 包括架構. 比方說:
>>  char s[10] = { 'x' }; /* s[0] 初始化為 'x', s[1]~s[9] 「補0」*/
>
>補0應該是從s[2]~s[9] 才對吧?
>s[1]是終結字元

請再仔細看清楚原文括號裡的東西. 'x' 跟 "x" 的分別你應該知道吧!


>>int ia[10] = { 123 }; /* ia[0] 初始化為 123, ia[1]~ia[9] 「補0」*/
>
>
>可能最近一直探討c字串的問題
>害我看到123 僅是一個元素的值嚇到...

為什麼元素的值不能是 123. char 的數值至少可以到 127, 更何況上面的例子是 int.


>想確定一下
>字元陣列的一個元素是不是不能塞好幾個字元?

你認為應該怎麼塞!?

作者 : ice_emissary(燃燒的大地) 貼文超過200則
[ 貼文 409 | 人氣 0 | 評價 1890 | 評價/貼文 4.62 | 送出評價 18 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/6 上午 10:38:19
這樓也蓋了好己層了。
我給樓主的建議是:請多多實際練習、操作、把東西做出來,從自己做當中的經驗感想來理解為什麼前人要這樣設計。

如果你認為只要發問-回答,在加上自己「想」,就可以理解來龍去脈的話,只能說你會花更多更多的時間還不一定能夠明白到底為什麼?

我從前叫你做的 strncpy, strcmp, strncat, ... 你一直都沒有做,我光從這點就可以大膽猜測你這問題還可以問兩年了!
所以我後來也懶得回答你。
倒是 Raymond 大不願意放棄的精神讓我滿感動的!
作者 : kotty123(存在)
[ 貼文 56 | 人氣 0 | 評價 10 | 評價/貼文 0.18 | 送出評價 12 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/6 下午 10:33:37
>你指的是:
>  『再補充一些題外話, 在視窗系統上, 有些 API 會需要一種特殊內容的字串, 它特殊的地方在於可以儲存多筆資料, 每一筆資料是以 0 值字元來分割的, 最後一筆資料用兩個 0 值字元來標示.』
>
>請注意看, 我說的是『最後一筆資料用兩個 0 值字元來標示』, 並不是『在後面補2個\0』.
>
>如果有兩筆資料: 「abc」跟 「xyz」, 用 nul-separated string 的格式來存放的話, 資料內容將會是:
>  'a', 'b', 'c', 0, 'x', 'y', 'z', 0, 0
>
>這裡的 0 不是終結字元, 是當作分隔字元. 資料本身是 { 'a', 'b', 'c' } 及 { 'x', 'y', 'z' }; 0 是一個特殊符號, 用來分隔資料. 最後一筆資料 { 'x', 'y', 'z' } 後面要兩個 0 來標示 end of data.
>
>不知道你怎麼會牽涉到「補 0」.


很抱歉....
當時誤以為你說的特殊定義字串的格式是 " "

而分隔字元那些我都瞭解,誤會一場










>不是! 我上面說的『特殊內容字串』, 用的例子是 nul-separated string. 特殊的地方不是字串後面有多少個 0,
 特殊的地方是要怎麼把多筆資料放在一個字元陣列裡. 一般多筆資料是用指標陣列來儲存:
>      +----+
>  data| *--+--> 'abc'
>      |----|
>      | *--+--> 'def'
>      |----|
>      | *--+--> 'ghi'
>      |----|
>      |NULL|
>      +----+
>
>但基於各種原因現在不想用指標陣列來做, 想要把所有資料放在一個字元陣列裡送出去. 你必須在原有資料內加入額外的訊息, 這樣才能知道每一筆資料在哪裡結束, 下一筆資料從哪裡開始, 整個資料何時結束. 方法有很多, 用 0 來分隔資料是其中一個方法.



是我表達不好,
我並不是覺得特殊的地方是陣列後面有幾個0,
而且是我看錯,抱歉抱歉..









>你完全沒有看懂我上面所說的對嗎? 如果你有看懂的話, 你就知道
>  char u[5] = 'abcdefg';
>因該是編譯錯誤!!!


但我當時編譯出來的結果只有警告
再編譯一次就沒警告了
我也把每個元素都顯示
我覺得我是對的
而可能是沒信心
所以我才再問一遍我這樣說是對的嗎
這樣子









>請再仔細看清楚原文括號裡的東西. 'x' 跟 'x' 的分別你應該知道吧!


這部分是我看錯了,抱歉









>為什麼元素的值不能是 123. char 的數值至少可以到 127, 更何況上面的例子是 int.



就可能是最近一直問c字串問題
也把單一個數字給想成字元了...






作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/7 上午 06:23:45
>>你完全沒有看懂我上面所說的對嗎? 如果你有看懂的話, 你就知道
>>  char u[5] = "abcdefg";
>>因該是編譯錯誤!!!
>
>
>但我當時編譯出來的結果只有警告

這個在上面也有提到:
  『有些 C 編譯器 (如 gcc) 的預設更為寬鬆, 允許 a4 能夠被編譯, 嚴格來說這是不符標準的.』

「警告」≠「編譯錯誤」.

「編譯錯誤」是完全不能編譯. 「警告」是能夠編譯, 不過編譯器認為某些句子有問題, 應該反映給程式員知道.

「警告」跟「錯誤」的分別應該是你已知道的基本知識.

雖然只有「警告」的原始碼可以完成編譯, 但程式員不應該忽略任何一個警告, 並盡量做到零警告. 「警告」的處理是另一個題目, 必須看句子甚至整個程式碼來個別處理. 沒有通用的方法.


>再編譯一次就沒警告了

如果你是用 IDE 或 make file 來編譯, 對 IDE 或 make utility 來說, 這是正常的行為 - 不是沒警告, 而是沒再編譯.

這也是你應該要知道的基本知識.

作者 : kotty123(存在)
[ 貼文 56 | 人氣 0 | 評價 10 | 評價/貼文 0.18 | 送出評價 12 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2015/9/7 下午 04:43:15
>這個在上面也有提到:
>  『有些 C 編譯器 (如 gcc) 的預設更為寬鬆, 允許 a4 能夠被編譯, 嚴格來說這是不符標準的.』
>
>「警告」≠「編譯錯誤」.
>
>「編譯錯誤」是完全不能編譯. 「警告」是能夠編譯, 不過編譯器認為某些句子有問題, 應該反映給程式員知道.
>
>「警告」跟「錯誤」的分別應該是你已知道的基本知識.
>
>雖然只有「警告」的原始碼可以完成編譯, 但程式員不應該忽略任何一個警告, 並盡量做到零警告. 「警告」的處理是另一個題目, 必須看句子甚至整個程式碼來個別處理. 沒有通用的方法.
>
>如果你是用 IDE 或 make file 來編譯, 對 IDE 或 make utility 來說, 這是正常的行為 - 不是沒警告, 而是沒再編譯.
>
>這也是你應該要知道的基本知識.
>




看來我要翻另一本書了
我這本書的內容沒有你說的 應該要知道的基本知識

 板主 : simula
 > C++ - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - C++ - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
C++
1 Raymond 13050 
2 青衫 4760 
3 simula 4690 
4 coco 4030 
5 白老鼠(Gary) 3670 
6 ozzy 2540 
7 Ben 2250 
8 Anderson 1960 
9 windblown 1650 
10 Kenny 1560 
C++
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2019 程式設計俱樂部 http://www.programmer-club.com.tw/
0.234375