【问题标题】:i have a problem with strcat into 2d array in c我在c中将strcat转换为二维数组有问题
【发布时间】:2024-04-17 00:45:01
【问题描述】:

我试图将文件中的单词添加到二维数组中,问题是在第 7 个单词之后,单词开始变得奇怪,有谁知道这可能会导致这种情况吗?

void count_words(WordCount **wclist, FILE *infile)
{
   int num_words = 0;
   char ch;
   int k=0;
   char **pook;
   int flagA=0;
   pook = malloc(4096*sizeof(char*));//creates a 2d array for every word from the file
   for(int i = 0 ; i <4096 ; i++)
   {
      pook[i] = malloc(50 * sizeof(char*));
   }
   while((ch=fgetc(infile))!=EOF)
   {
      
      ch=tolower(ch);
      if(flagA==0)
      {
         if(isalpha(ch)!=0)
         {
            num_words++;
            flagA=1;
            strcat(pook[k]+0, &ch);
         }
      }
      else
      {
         if(isalpha(ch)!=0)
         {
            strcat(pook[k]+0, &ch);
         }
         else
         {
            flagA = 0;
            k++;
         }
      }
   }




   for(int i =0 ; i < num_words ;i++)
   {
      printf("%s\n",pook[i]);
      add_word(wclist , pook[i]);
   }
}

输入:

input is text file that contains :
ilona.txt
main.c
makefile
wc_sort.o
word_count.c
word_count.h
words

这是输出的样子: 伊洛纳 文本文件 主要的 C 生成文件 厕所 种类 ○ 单词 数数 C 单词 数数 H 单词


这才是真正的输出:

the output is :
ilona
txt
main
c
makefile
wc
sort
o
w o r d
c
o
u
n
t

c

w
 o
  r
   d

t
h
words
*/

【问题讨论】:

  • 不是bug,但pook[i] = malloc(50 * sizeof(char*));不应该是pook[i] = malloc(50 * sizeof(char));(为49个字符串加上空终止符分配空间)?
  • fgetc 的返回值应存储在int 变量中,因为EOF 可能无法由char 变量表示。因此ch 应该是int
  • 仅基于您的函数名称,我看不出需要任何动态分配whatsoever。仅仅因为你可以并不意味着你应该。 read_words 似乎更适合您似乎想要做的事情。
  • 另外关于strcat,第一个参数指向一个分配的内存块,它最初具有不确定的内容。如果稍后将其传递给strcat,则需要在分配后将第一个字节初始化为0。

标签: c loops multidimensional-array malloc strcat


【解决方案1】:

所以你的代码有几个错误,我相信随着你的经验的积累,你的代码会变得不那么混乱。

之前的cmet已经指出了一些bug,所以我就按顺序列出来吧:

  1. 当您使用 'malloc' 时,它不会重置内存单元中的值,因此您要么自己做,要么按照我的建议,只使用 'calloc' - 这是 IMO 的一个更好的习惯。

  2. 您应该检查您分配内存的指针是否没有收到 NULL 值(因为分配失败)。

  3. 您首先为指向字符数组的指针分配内存(也称为字符串数),然后为每个字符串的字符数分配内存)。请注意,您有一个错误:pook[i] = malloc(50 * sizeof(char*));。这应该是pook[i] = malloc(50 * sizeof(char));,因为第二次分配是用于字符而不是指向字符的指针。

  4. 虽然strcat(pook[k]+0, &amp;ch); 语句应该没问题,因为 &ch 是一个指向字符的指针,例如声明一个数组并使用指向数组的指针,但请注意大多数编译器可能不会让你这样做;事实上,我尝试在 VS 2019 中编译你的代码,它甚至不让我构建它,因为 strcat 是一个不安全的函数。

  5. pook[k]+0 中,零是无关紧要的,并且可能会导致编译问题,因为它有时可能会将其识别为算术参数,而不是指针。

  • 另外,IMO 您应该在上传代码之前添加 cmets,这样其他人会更容易理解您的代码并帮助您更快地找到解决方案,从而节省您的时间。此外,这是一个必须做的习惯,因为您几乎总是会向其他人展示您的代码,甚至在您迷失自己的代码时帮助您。

你尝试做的我的版本如下:

void count_words (FILE* infile)
{
    char** pook;
    pook = calloc(4096,sizeof(char*)); // Allocate the number of strings
    for (int i = 0; i < 4096; i++)
    {
        pook[i] = calloc(50, sizeof(char)); // Allocate the number of characters for each string
    }
    
    int num_words = 0, letter = 0; // Initialize a counter for the amount of words and letters
    int flag = 0; // Initialize a flag that represents if we are currently in a word or not.
    char ch; // A temp character

    while ((ch = fgetc(infile)) != EOF)
    {
        if (isalpha(ch) == 0 && flag == 0) // If the current character isn't a letter, and we didn't start to read a word:
            continue;

        else if (isalpha(ch) == 0 && flag == 1) // If the current character isn't a letter, and we finished to read a word:
        {
            ++num_words; // Because we finished reading a new word
            flag = 0; // Because we're not in a word anymore
            letter = 0; // Same as above
        }

        else if (isalpha(ch) != 0 && flag == 0) // If this is the first letter in the current word:
        {
            pook[num_words][letter] = ch; // Insert the value of the current character
            ++letter; // Advance to the next letter of pook[num_words]
            flag = 1; // Because we're currently in a word
        }
            
        else if (isalpha(ch) != 0 && flag == 1) // If this is not the first letter of the current word:
        {
            pook[num_words][letter] = ch; // Insert the value of the current character
            ++letter; // Advance to the next letter of pook[num_words]
        }
    } 

    if (flag == 1) // If the last character before the EOF is still part of the word, we need to increment the num of words.
        ++num_words;

    for (int i = 0; i < num_words; i++)
    {
        printf("%s\n", pook[i]);
    }
}

输出如下:

ilona
txt
main
c
makefile
wc
sort
o
word
count
c
word
count
h
words

希望我能帮上忙, 祝你好运!

【讨论】:

  • sizeof char 根据定义 1,因此可以进一步简化。