[英]I'm trying to make string parser but something is going wrong
我試圖制作一個文本解析器,它根據空格字符分隔字符串中的單詞。 但是,出了點問題。
#include <stdio.h>
#include <string.h>
int main() {
//the string should end with a space to count the all words
char name[30] = "hello world from jordan ";
int start = 0;
int end = strlen(name);
int end_word = start;
char full[20][20];
memset(full, 0, 400);
int number_of_words = 0;
for (int w = 0; w < end; w++) {
if (name[w] == ' ') {
number_of_words++;
}
}
int counter = 0;
while (counter < number_of_words) {
for (int i = start; i < end; i++) {
if (name[i] == ' ') {
start = i;
break;
}
}
for (int j = end_word; j < start; j++) {
full[counter][j] = name[j];
}
end_word = start;
start++;
counter++;
}
for (int x = 0; x < 20; x++) {
for (int y = 0; y < 20; y++) {
printf("%c", full[x][y]);
}
printf("%d", x);
}
return 0;
}
這是我運行代碼時發生的奇怪事情:
hello0 world1 from2 jor3dan45678910111213141516171819
前三個詞正在以正確的方式初始化,但第四個不是,我不知道為什么會這樣。
我想要對問題的解釋,如果可能的話,我想要一種更有效的方式來編寫此代碼,而無需使用指針。
注意:我是初學者,這就是為什么我要求沒有指針的解決方案。
首先,試圖避免 C 中的指針將(非常)困難。 就其性質而言,arrays 在您想對它們做任何有用的事情時立即成為指針。 數組訂閱是指針算法的語法糖( foo[2]
與*(foo + 2)
相同)。 將數組傳遞給 function 將導致它衰減到指向第一個元素的指針。
無論您是否意識到,您都會在代碼中多次使用指針。
至於代碼...
快速說明: size_t
,而不是int
,是使用 memory 大小/索引時使用的適當類型。 我將在代碼的“更正”版本中使用它,您應該嘗試在一般情況下使用它,繼續前進。
output 有點令人困惑,因為所有內容都打印在一行上。 讓我們清理一下,並添加一些調試信息,例如您存儲的每個字符串的長度。
for (size_t x = 0; x < 20; x++) {
printf("%zu [length: %zu]: ", x, strlen(full[x]));
for (size_t y = 0; y < 20; y++)
printf("%c", full[x][y]);
putchar('\n');
}
現在我們得到 output,跨越幾行(為簡潔起見,一些重復折疊),如下:
0 [length: 5]: hello
1 [length: 0]: world
2 [length: 0]: from
3 [length: 0]: jor
4 [length: 3]: dan
5 [length: 0]:
...
19 [length: 0]:
從這里我們可以看到一些值得注意的事情。
0
,並且似乎包含空格。 零長度意味着我們的一些arrays以空終止字節( '\0'
)開頭,我們只看到 output 因為我們手動遍歷每個數組的整體。
請注意,當要打印 null 字符時,大多數終端將“什么都不做”,這意味着我們似乎直接跳到了我們的“字符串”。 我們可以通過總是打印一些東西來更好地可視化正在發生的事情:
printf("%c", full[x][y] ? full[x][y] : '*');
在這種情況下,當我們遇到 null 字符時,我們會打印一個星號,從而得到 output:
0 [length: 5]: hello***************
1 [length: 0]: ***** world*********
2 [length: 0]: *********** from****
3 [length: 0]: **************** jor
4 [length: 3]: dan*****************
5 [length: 0]: ********************
...
19 [length: 0]: ********************
這非常清楚地顯示了我們的角色在 memory 中的位置。
主要問題是在這個循環中
for (int j = end_word; j < start; j++) {
full[counter][j] = name[j];
}
j
被初始化為相對於name
開頭的 position ,但用於索引full
的 memory 偏移量。 排除我們的第一個 substring,當end_word
為0
時,這使我們離每個子數組的第零個索引越來越遠,最終跨越 arrays 之間的邊界。
這恰好起作用,因為 C 中的 2D arrays 在 memory 中連續布局。
為了解決這個問題,我們必須使用一個單獨的索引來復制我們的字符,每個子數組從零開始。
for (size_t j = end_word, k = 0; j < start; j++, k++) {
full[counter][k] = name[j];
}
現在,當我們打印 arrays 時,我們可以將自己限制在已知的number_of_words
( for (size_t x = 0; x < number_of_words; x++)
),給我們 output:
0 [length: 5]: hello***************
1 [length: 6]: world**************
2 [length: 5]: from***************
3 [length: 7]: jordan*************
這看起來大致正確,但在“單詞”中包含了前面的空格。 我們可以通過將end_word
設置為下一個字符來跳過這些空格:
start++;
end_word = start;
counter++;
現在我們的 output 看起來正確拆分:
0 [length: 5]: hello***************
1 [length: 5]: world***************
2 [length: 4]: from****************
3 [length: 6]: jordan**************
請注意,這些是(現在已正確格式化)以空字符結尾的字符串,並且可以使用%s
說明符打印,如下所示:
for (size_t x = 0; x < number_of_words; x++)
printf("%zu [length: %zu]: %s\n", x, strlen(full[x]), full[x]);
總的來說,這有點脆弱,因為它需要尾隨定界空間才能工作,並且每次重復定界空格時都會創建一個空字符串(或者如果源字符串以空格開頭)。
順便說一句,這個類似的示例應該展示一種用於標記字符串的直接方法,同時跳過所有分隔符,並包含一些重要的注釋。
#include <stdio.h>
#include <string.h>
int main(void) {
char name[30] = "hello world from jordan";
char copies[20][30] = { 0 };
size_t length_of_copies = 0;
size_t hold_position = 0;
size_t substring_span = 0;
size_t i = 0;
do {
/* our substring delimiters */
if (name[i] == ' ' || name[i] == '\0') {
/* only copy non-zero spans of non-delimiters */
if (substring_span) {
/* `strncpy` will not insert a null terminating character
* into the destination if it is not found within the span
* of characters of the source string...
*/
strncpy(
copies[length_of_copies],
name + hold_position,
substring_span
);
/* ...so we must manually insert a null terminating character
* (or otherwise rely on our memory being initialized to all-zeroes)
* */
copies[length_of_copies++][substring_span] = '\0';
substring_span = 0;
}
/* let's assume our next position will be the start of a substring */
hold_position = i + 1;
} else
substring_span++;
/* checking our character at the end of the loop,
* and incrementing after the fact,
* let's us include the null terminating character as a delimiter,
* as we will only fail to enter the loop after processing it
*/
} while (name[i++] != '\0');
for (size_t i = 0; i < length_of_copies; i++)
printf("%zu: [%s]\n", i + 1, copies[i]);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.