2017-08-14 18 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

相关问题