2017-08-14 76 views
3

編輯:我曾嘗試改變線arr_of_strings[arr_index_count] = first_word;strcpy(arr_of_strings[arr_index_count], first_word);但隨後它給打印Word is: This字符串無法正常被清空,並分配了的strcpy打交道時(字符串,「」)

編輯2後分段錯誤:我我試圖做到這一點沒有strtok,因爲我認爲這將是瞭解C字符串的好方法。

試圖學習C我自己。決定創建一個接受字符串的函數,並將字符串中的每個單詞放入數組中的一個元素中。這裏是我的代碼:

假設#define MAX_LENGTH = 80

// char *string_one[unknown_size]; 

// first_word will represent each word in the sentence 
char first_word[MAX_LENGTH + 1] = ""; 

// this is the array I will store each word in 
char *arr_of_strings[MAX_LENGTH]; 

int index_count = 0; 
int arr_index_count = 0; 

char sentence[] = "This is a sentence."; 

for (int i = 0; i<MAX_LENGTH; i++) { 
    printf("Dealing with char: %c\n", sentence[i]); 

    if (sentence[i] == '\0') { 
     // end of sentence 
     break; 
    } else if (sentence[i] == ' ') { 
     // this signifies the end of a word 
     printf("Word is: %s\n", first_word); 
     arr_of_strings[arr_index_count] = first_word; 
     // after putting the word in the string, make the word empty again 
     strcpy(first_word, ""); 
     // verify that it is empty 
     printf("First word is now: %s\n", first_word); 

     index_count = 0; 
     arr_index_count++; 
    } else { 
     // not the start of a new string... so keep appending the letter to first_word 
     printf("Letter to put in first_word is: %c\n", sentence[i]); 
     first_word[index_count] = sentence[i]; 
     index_count++; 
    } 
} 

printf("-----------------\n"); 
for (int j = 0; j<=arr_index_count; j++) { 
    printf("%s\n", arr_of_strings[j]); 
} 

這是什麼版畫是:

Dealing with char: T 
Letter to put in first_word is: T 
Dealing with char: h 
Letter to put in first_word is: h 
Dealing with char: i 
Letter to put in first_word is: i 
Dealing with char: s 
Letter to put in first_word is: s 
Dealing with char: 
Word is: This 
First word is now: 
Dealing with char: i 
Letter to put in first_word is: i 
Dealing with char: s 
Letter to put in first_word is: s 
Dealing with char: 
Word is: isis 
First word is now: 
Dealing with char: a 
Letter to put in first_word is: a 
Dealing with char: 
Word is: asis 
First word is now: 
Dealing with char: s 
Letter to put in first_word is: s 
Dealing with char: e 
Letter to put in first_word is: e 
Dealing with char: n 
Letter to put in first_word is: n 
Dealing with char: t 
Letter to put in first_word is: t 
Dealing with char: e 
Letter to put in first_word is: e 
Dealing with char: n 
Letter to put in first_word is: n 
Dealing with char: c 
Letter to put in first_word is: c 
Dealing with char: e 
Letter to put in first_word is: e 
Dealing with char: . 
Letter to put in first_word is: . 
Dealing with char: 
----------------- 
sentence. 
sentence. 
sentence. 

如果我們看看這裏:

First word is now: 
Dealing with char: i 
Letter to put in first_word is: i 
Dealing with char: s 
Letter to put in first_word is: s 
Dealing with char: 
Word is: isis 
  1. 怎麼來的,當字是空的,我們把is進去吧,單詞現在是isis? (與asis相同)。

  2. 爲什麼字sentence被打印3次?我的算法顯然是有缺陷的,但是如果有的話,不應該打印4次(對於句子中的每個單詞一次:這是一個句子)這個詞sentence

此外,我只是學習C所以,如果有任何其他的方法來改進算法,請讓我知道。

+2

'arr_of_strings'是char指針數組,而你點他們都在同一字符數組'first_word' –

+1

..完全。而且你不寫一個null結束符,所以「this」被「is」 - >「isis」覆蓋,依此類推。 – alain

+0

@ M.M我試圖將該行更改爲'strcpy(arr_of_strings [arr_index_count],first_word);'但是它在打印後出現分段錯誤'Word is:This' – user2719875

回答

1

基於我的strtok-free answer,我編寫了一些使用char指針數組而不是硬編碼的2D矩陣的代碼。

char matrix[N][LEN]是一個二維數組,能夠存儲多達N的字符串,其中每個字符串可以有LEN作爲其最大長度。 char *ptr_arr[N]是一個包含N字符指針的數組。所以它最多可以存儲N字符串,但每個字符串的長度都沒有定義。

目前的做法可以讓我們節省一些空間,根據需要爲每個字符串恰好分配儘可能多的內存。使用硬編碼的二維數組,您可以爲任何字符串使用相同的內存;所以如果你假設一個字符串的長度可以是20,那麼你會分配一個大小爲20的內存塊,而不管你存儲的字符串的大小是多少,甚至更大 - 甚至更大。在後面的情況下,您需要中斷字符串,或者如果代碼沒有仔細寫入,請通過超出存儲字符串的數組的邊界來調用未定義的行爲

隨着指針的做法我們並不需要擔心這一點,可以分配,我們需要爲每個字符串儘可能多的空間,但一如既往,權衡存在。我們可以做到這一點,並節省一些空間,但我們需要動態分配內存(並完成它,取消分配它; C中沒有垃圾回收器,例如在Java中)。動態分配是一個強大的工具,但需要我們花費更多的開發時間。

所以,在我的例子中,我們將遵循同樣的邏輯(關於我們如何找到字符串等詞)之前,但我們會小心的有關存儲在矩陣中的話。

一旦找到一個單詞並將其存儲在臨時數組word中,我們可以使用strlen()找出該單詞的確切長度。我們將動態分配與單詞建議的長度一樣多的空間,再加上1表示空終止符,即所有C字符串應具有的值(因爲<string.h>取決於該值以查找字符串的結尾)。

其結果是,用於存儲的第一個字,「亞歷山大」,我們需要做的:

ptr_arr[0] = malloc(sizeof(char) * (9 + 1)); 

,其中9是strlen("Alexander")結果。請注意,我們要求的內存塊的大小等於char的大小,次數爲10次。char的大小爲1,因此在這種情況下它不會做任何更改,但通常您應該使用該你可能想要其他數據類型或結構等)。

我們做陣列指向我們只是動態分配的內存塊的第一個指針。現在這個內存塊屬於我們,因此允許我們在其中存儲數據(在我們的例子中是這個詞)。我們用strcpy()來做到這一點。

然後我們繼續打印文字。

現在我們做,在Python例如,您可以用編寫代碼完成你的程序。但是現在,既然我們動態分配內存,我們需要free()吧!這是人們常犯的錯誤;忘記釋放他們所要求的記憶!

我們通過釋放指向由malloc()返回的內存的每個指針來做到這一點。所以如果我們調用malloc() 10次,那麼free()應該調用10次 - 否則應該發生內存泄漏!

夠說話,這裏是代碼:

#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 

#define N 100 

int fill(char* ptr_arr[N], char* data) 
{ 
    // How many words in 'data'? 
    int counter = 0; 
    // Array to store current word, assuming max length will be 50 
    char word[50]; 
    // Counter 'i' for 'word' 
    int i; 
    // Wihle there is still something to read from 'data' 
    while(*data != '\0') 
    { 
     // We seek a new word 
     i = 0; 
     // While the current character of 'data' is not a whitespace or a null-terminator 
     while(*data != ' ' && *data != '\0') 
      // copy that character to word, and increment 'i'. Move to the next character of 'data'. 
      word[i++] = *data++; 
     // Null-terminate 'word'. 'i' is already at the value we desire, from the line above. 
     word[i] = '\0'; 
     // If the current of 'data' is not a null-terminator (thus it's a whitespace) 
     if(*data != '\0') 
      // Increment the pointer, so that we skip the whitespace (and be ready to read the next word) 
      data++; 
     // Dynamically allocate space for a word of length `strlen(word)` 
     // plus 1 for the null terminator. Assign that memory chunk to the 
     // pointer positioned at `ptr_arr[counter]`. 
     ptr_arr[counter] = malloc(sizeof(char) * (strlen(word) + 1)); 
     // Now, `ptr_arr[counter]` points to a memory block, that will 
     // store the current word. 

     // Copy the word to the counter-th row of the ptr_arr, and increment the counter 
     strcpy(ptr_arr[counter++], word); 
    } 

    return counter; 
} 

void print(char* matrix[N], int words_no) 
{ 
    for(int i = 0; i < words_no; ++i) 
     printf("%s\n", matrix[i]); 
} 

void free_matrix(char* matrix[N], int words_no) 
{ 
    for(int i = 0; i < words_no; ++i) 
     free(matrix[i]); 
} 

int main(void) 
{ 
    char data[] = "Alexander the Great"; 
    // We will store each word of 'data' to a matrix, of 'N' rows and 'LEN' columns 
    char *matrix[N]; 
    int words_no; 
    // 'fill()' populates 'matrix' with 'data' and returns the number of words contained in 'data'. 
    words_no = fill(matrix, data); 
    print(matrix, words_no); 
    free_matrix(matrix, words_no); 
    return 0; 
} 

輸出:

Alexander 
the 
Great 
2

arr_of_strings只是char指針的一個數組,然後您將所有單詞指向數組first_word。此外,您不使用C字符串所需的空終止符。


這裏有一個方法,可以幫助你,它使用strtok

#include <string.h> 
#include <stdio.h> 

#define N 100 
#define LEN 20 // max length of a word 

int fill(char matrix[N][LEN], char* data) 
{ 
    // How many words in 'data'? 
    int counter = 0; 
    char * pch; 
    // Splits 'data' to tokens, separated by a whitespace 
    pch = strtok (data," "); 
    while (pch != NULL) 
    { 
     // Copy a word to the correct row of 'matrix' 
     strcpy(matrix[counter++], pch); 
     //printf ("%s\n",pch); 
     pch = strtok (NULL, " "); 
    } 
    return counter; 
} 

void print(char matrix[N][LEN], int words_no) 
{ 
    for(int i = 0; i < words_no; ++i) 
     printf("%s\n", matrix[i]); 
} 

int main(void) 
{ 
    char data[] = "New to the C programming language"; 
    // We will store each word of 'data' to a matrix, of 'N' rows and 'LEN' columns 
    char matrix[N][LEN] = {0}; 
    int words_no; 
    // 'fill()' populates 'matrix' with 'data' and returns the number of words contained in 'data'. 
    words_no = fill(matrix, data); 
    print(matrix, words_no); 
    return 0; 
} 

輸出:

New 
to 
the 
C 
programming 
language 
+1

啊,我實際上正在試圖在沒有'strtok'的情況下這麼做,因爲它認爲這將是獲取C字符串的好方法。對不起,應該在帖子中提到過。我會用'strtok'來檢查你的代碼,不過既然我可能會從中學習,所以在此先感謝。 – user2719875

2

1)這是發生,因爲你不加「\ 0「到打印出來之前的單詞結尾。在你的程序遇到第一個空間first_word看起來像這樣{'T', 'h', 'i', 's', '\0', '\0', ...},並打印出來就好了。調用strcpy(first_word, "")將其更改爲{'\0', 'h', 'i', 's', '\0', ...},然後在下一個單詞「is」中讀取將覆蓋字符串的前兩個字符,從而產生{'i', 's', 'i', 's', '\0', ...},因此first_word現在是字符串「isis」,如輸出中所示。這可以通過在打印字符串之前簡單地添加first_word[index_count] = '\0'來解決。

2.1)這個數組包含每個索引相同的字符串是因爲你的字符串數組arr_of_strings是字符串指針數組的原因,最終都指向同一個字符串first_word其中將包含在最後一句的最後一個字的循環。這是可以解決的一對夫婦的方式與其中之一是使arr_of_strings二維陣列狀char arr_of_strings[MAX_STRINGS][MAX_LENGTH],然後你將與strcpy(arr_of_strings[arr_index_count], first_word)

2.2添加到字符串數組)最後的原因,它只能打印「的句子。」三次是因爲你只檢查一個空間來表示單詞的結尾。 「句子。」以null結束符'\ 0'結尾,因此它永遠不會被添加到單詞數組中,並且輸出也沒有一行「Word is:sentence」。

+0

感謝您的解釋。當你說「通過在打印字符串之前加上first_word [index_count] ='\ 0'',你的意思是在這行之前:'printf(」第一個字現在是:%s \ n「,first_word);' ?所以假設'first_word'目前是'This'和'''',是不是隻是把''''改成'\ 0'?然後下一行使它成爲'\ 0his \ 0 \ 0 \ 0 \ 0'。然後用「a」使它成爲「a \ 0s \ 0 \ 0」,那麼打印這個詞就是'a'?編輯:我沒有添加你提到的行,現在它打印'字是:這個''字是:isis''字是:as' – user2719875

+0

好吧,關於2.1)。爲什麼需要'char arr_of_strings [MAX_STRINGS] [MAX_LENGTH]',爲什麼'char * arr_of_strings [MAX_LENGTH]'(原始方式)不起作用?根據我的理解,每個元素都指向一個字符串,對吧?因此,'strcpy(arr_of_strings [arr_index_count],first_word)'使數組char * arr_of_strings [MAX_LENGTH]中的元素指向字符串'first_word'的內容? – user2719875

+0

哦,最後,char arr_of_strings [MAX_STRINGS] [MAX_LENGTH]'如何讀寫?它是「MAX_STRING元素的數組,每個元素是一個char,每個char的最大長度是MAX_LENGTH」?所以'[[[長度爲MAX_LENGTH的字符],[長度爲MAX_LENGTH的字符等]]?在這種情況下,內部數組不應該是'char *'嗎?那麼像'char * arr_of_strings [MAX_STRINGS] [MAX_LENGTH]'? – user2719875

1

試圖做到這一點沒有strtok,因爲我認爲這將是瞭解C字符串的好方法。

是的,這就是精神!


我已經解釋你的代碼的一些問題,我以前的答案,所以現在我要發佈一個免費的strtok的解決方案,這將肯定有助於你理解這是怎麼回事用字符串。基本的指針算術將被使用。

Pro-tip:使用一張紙並繪製陣列(datamatrix),注意其計數器的值,然後運行該文件中的程序。

代碼:

#include <string.h> 
#include <stdio.h> 

#define N 100 
#define LEN 20 // max length of a word 

int fill(char matrix[N][LEN], char* data) 
{ 
    // How many words in 'data'? 
    int counter = 0; 
    // Array to store current word 
    char word[LEN]; 
    // Counter 'i' for 'word' 
    int i; 
    // Wihle there is still something to read from 'data' 
    while(*data != '\0') 
    { 
     // We seek a new word 
     i = 0; 
     // While the current character of 'data' is not a whitespace or a null-terminator 
     while(*data != ' ' && *data != '\0') 
      // copy that character to word, and increment 'i'. Move to the next character of 'data'. 
      word[i++] = *data++; 
     // Null-terminate 'word'. 'i' is already at the value we desire, from the line above. 
     word[i] = '\0'; 
     // If the current of 'data' is not a null-terminator (thus it's a whitespace) 
     if(*data != '\0') 
      // Increment the pointer, so that we skip the whitespace (and be ready to read the next word) 
      data++; 
     // Copy the word to the counter-th row of the matrix, and increment the counter 
     strcpy(matrix[counter++], word); 
    } 

    return counter; 
} 

void print(char matrix[N][LEN], int words_no) 
{ 
    for(int i = 0; i < words_no; ++i) 
     printf("%s\n", matrix[i]); 
} 

int main(void) 
{ 
    char data[] = "Alexander the Great"; 
    // We will store each word of 'data' to a matrix, of 'N' rows and 'LEN' columns 
    char matrix[N][LEN] = {0}; 
    int words_no; 
    // 'fill()' populates 'matrix' with 'data' and returns the number of words contained in 'data'. 
    words_no = fill(matrix, data); 
    print(matrix, words_no); 
    return 0; 
} 

輸出:

Alexander 
the 
Great 

代碼的要點在於在功能fill(),這需要data和:

  1. 查找一個字。
  2. 將該字逐個字符存儲到名爲word的數組中。
  3. 將此字詞拷貝至matrix

棘手的部分是找到這個詞。你需要迭代字符串並在遇到空白字符時停下來,這表明我們在該迭代中讀取的每個字符實際上都是單詞的字母。

但是,在搜索字符串的最後一個單詞時需要小心,因爲當達到該點時,您將不會遇到空白字符。出於這個原因,你應該小心地到達字符串的末尾;換句話說:空終止符。

當你這樣做的時候,複製矩陣中的最後一個單詞,你就完成了,但是一定要正確更新指針(這是我給你的紙理念在理解上會有很大的幫助)。

+0

好的,謝謝。目前正在審查這項權利。 char matrix [N] [LEN]'如何讀/寫?它是「一個由N個字符組成的數組,每個字符指向另一個LEN字符數組嗎?」?所以寫出來就像'[[長度爲LEN的char數組],[長度爲LEN的char數組],[長度爲LEN的char數組],... N]'?如果是,那麼它與'char * matrix [N]'(它是一個「N個字符串數組」,即[[[string],[string],[string],... N] )? – user2719875

+1

'char matrix [N] [LEN]'是一個二維數組,能夠存儲多達'N'個字符串,其中每個字符串都可以具有'LEN'作爲其最大長度。 'char * matrix [N]'是一個由'N'個字符指針組成的數組。所以它可以存儲多達'N'個字符串,但是每個字符串的長度都沒有定義。希望可以幫助@ user2719875,歡迎您! =)你想讓我修改這個例子並使用'char * matrix [N]'? – gsamaras

+0

是的請!你現在可以離開你現在使用'char matrix [N] [LEN]'的例子嗎?這對於未來的讀者來說也會非常有幫助,我認爲(我來自Python背景,因此處理字符串是非常不同的)。 (我的問題是關於「所以它最多可以存儲N個字符串,但每個字符串的長度都沒有定義」是,如果有的話,這不應該是件好事嗎?在我們不知道每個單詞有多長時間的情況下...即,如果用戶輸入了單詞超過20個單詞的句子,那麼我們使用'char * matrix [N]'的代碼仍然可以按照每個單詞剪切每個單詞到len 20)。 – user2719875