【问题标题】:Use of array of arrays of string in C for parsing text file在 C 中使用字符串数组来解析文本文件
【发布时间】:2013-03-15 10:43:13
【问题描述】:

我想从 N 个文本文件中读取(具有相似的结构:几行,每行具有相同的少量单词)并将读取的单词存储在字符串矩阵中,这样每个(行, col) 位置我有一个词。

文件的简单示例(两行,每行三个单词)如下:

line1word1 line1word2 line1word3
line2word1 line2word2 line2word3

单词的分隔符是空格。

我已经尝试过这段代码:

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

#define MAX_STRING_LENGTH 1000
#define MAX_TOKS 100
#define DELIMITERS " "

// line parsing utility
int parseString(char* line, char*** argv) {

  char* buffer;
  int argc;

  buffer = (char*) malloc(strlen(line) * sizeof(char));
  strcpy(buffer,line);
  (*argv) = (char**) malloc(MAX_TOKS * sizeof(char**));

  argc = 0;  
  (*argv)[argc++] = strtok(buffer, DELIMITERS);
  while ((((*argv)[argc] = strtok(NULL, DELIMITERS)) != NULL) &&
     (argc < MAX_TOKS)) ++argc;
  return argc; 
}


int main() {

  char S[MAX_STRING_LENGTH];
  char **A;

  int  n,i,j,l;

  FILE *f;
  char file[50];

  char ***matrix;
  matrix = malloc(MAX_TOKS * sizeof(char**));

 //memory allocation for matrix
 for (i = 0; i < MAX_TOKS; i++)
     {
       matrix[i] = malloc(MAX_TOKS * sizeof(char *));
       for (j = 0; j < MAX_TOKS; j++)
           {
           matrix[i][j] = malloc(MAX_TOKS * sizeof(char));
           }
     }

  int NFILE = 10; // number of files to be read

  for(i=0;i<NFILE;i++) 
    {  
    sprintf(file,"file%d.txt",i); 
    f = fopen(file,"r");

    l=0; // line-in-file index
    while(fgets(S,sizeof(S),f)!=NULL) {
          n = parseString(S,&A);
          for(j=0;j<n;j++) {
            matrix[i][l]=A[j];
            printf("%s\t%s\n",matrix[i][l],A[j]); 
            } 
        l++;
        } 
 fclose(f); 
    }

free(matrix);
free(A);    
return(0);  
}

我无法解决的问题是,在检查数组之间的对应关系时(以确保我正确存储单个单词)使用

printf("%s\t%s\n",matrix[i][l],A[j]);

我发现每一行的最后一个单词(并且只有最后一个单词),无论文件编号如何,都没有存储在matrix 中。也就是说file0中的line1word1line1words正确存储在matrix[0][0][0]matrix[0][0][1]中,但是在matrix[0][0][2]字段中没有line1word3,即使A[2]有!

我做错了什么?有什么建议吗?

提前非常感谢, 干杯

【问题讨论】:

    标签: c string matrix


    【解决方案1】:

    char ***matrix 没有声明一个三维数组。您的矩阵需要类似于 char *matrix[a][b] 来保存字符串指针的二维数组。为了计算数组中的地址,编译器需要知道除一个之外的所有维度。如果你仔细想想,你可能会明白为什么……

    如果你有两个数组:

    1 2 3        1  2  3  4  5  6  7
    4 5 6        8  9 10 11 12 13 14
    7 8 9       15 16 17 18 19 20 21
    

    您可以看到item[1][1] 不是同一个项目。无论数组中的维度如何,元素通常在内存中按顺序排列,每一行都在前一个(或可能的列,我想取决于语言)之后。如果你有一个指针数组,实际内容可能在其他地方,但点会这样排列。因此,在我上面的示例中,您必须向编译器提供列数,以便它可以找到成员(rows 的数量可以是可变的。)在三维数组中,您必须提供第一个 TWO 维度,以便编译器可以计算项目偏移量。

    希望对你有帮助。

    编辑:您可以通过创建自己的函数来处理所有数组项访问,从而获得真正的动态数组维度。该函数需要知道动态尺寸和项目索引,以便计算适当的地址。

    【讨论】:

      【解决方案2】:

      这看起来不对:buffer = (char*) malloc(strlen(line) * sizeof(char));

      首先,在 C 中不需要强制转换 malloc。如果你的代码没有强制转换就无法编译,可能有两个原因:

      1. 没有 malloc 的原型。显然这会导致问题,因为没有原型意味着函数返回默认类型:int,否则会发生错误。这可能会导致您的程序行为不端。为避免这种情况,#include &lt;stdlib.h&gt;
      2. 您正在使用 C++ 编译器。停止。使用 C++ 编程(停止使用 malloc)或使用 C 编译器。如果您想在 C++ 项目中使用此项目,请使用 C 编译器编译您的 C 代码并在您的 C++ 编译器中链接到它。

      其次,sizeof(char)永远是1,不用乘。

      第三,字符串是一个以第一个'\0'结尾的字符序列。这意味着一个字符串总是至少占用 1 个字符,即使它是一个空字符串。 strlen("") 返回什么? sizeof("") 是什么?您需要加 1 为“\0”腾出空间:buffer = malloc(strlen(line) + 1);

      这看起来有点不对劲:(*argv) = (char**) malloc(MAX_TOKS * sizeof(char**));

      malloc 返回一个指向对象的指针。 *argv 是一个char **,这意味着它指向一个char *。但是,在这种情况下 malloc 返回一个指向 char ** 对象的指针。表示不需要相同。为避免与此相关的可移植性问题,请遵循此模式variable = malloc(n * sizeof *variable); ...在这种情况下,*argv = malloc(MAX_TOKS * **argv);

      随着时间的推移,它变得更加坚韧。忘记你认为你知道的关于你的代码的一切;假装你将在 24 个月后回到这个状态。您对此有何看法?

      argc = 0;  
      (*argv)[argc++] = strtok(buffer, DELIMITERS);
      while ((((*argv)[argc] = strtok(NULL, DELIMITERS)) != NULL) &&
         (argc < MAX_TOKS)) ++argc;
      

      这里实际上也有一对一。假设argc == MAX_TOKS,您的循环将尝试分配给(*argv)[MAX_TOKS]。这个循环是我认为您的问题所在,解决方案是更清楚地表达您的意图,而不是试图将尽可能多的代码塞进一行。你会如何重写这个?在这种情况下,我会这样做:

      char *arg;
      size_t argc = 0;
      do {
          arg = strtok(buffer, DELIMITERS);
          buffer = NULL;
      
          (*argv)[argc] = arg;
          argc++;
      } while (argc < MAX_TOKS && arg != NULL);
      

      问题是当 strtok 返回 NULL 时,您的解析循环不会增加。因此,您的函数返回最后一项的位置。假设您有两个标记,您的解析函数将返回 1。您的显示循环显示最多但不包括此位置的项目:for(j=0;j&lt;n;j++)。您可以使用建议的改进,或更改您的循环:for (j = 0; j &lt;= n; j++)。无论哪种方式,您都需要逐个修复这些问题。

      出于好奇,你在看哪本书?

      【讨论】:

      • 解析子程序是我在 tutorial 的 Program-10 中找到的子程序
      • 非常感谢您的帮助。我真的通读了它并根据您的建议更改了我的代码,但问题没有解决:每行的最后一个单词没有存储,我无法回忆它。 (顺便说一句,我想 +1 你的答案,但我没有足够的分数来获得这个特权,对不起)
      • @CarloAlberto:我看不到您问题中的代码有任何更改。如果您不向我展示新代码,我如何验证您是否已对我看到的问题进行了更正,并且这些更正不会引发更多问题?我如何帮助您处理我看不到的代码?请更新您的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多