[英]Use of array of arrays of string in C for parsing text file
我想从N个文本文件中读取(结构相似:几行,每行具有相同的少量单词),并将读取的单词存储在字符串矩阵中,使得每个行(行,列)位置,我有一个字。
文件的一个简单样本(两行,每行三个单词)如下:
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
。 也就是说, line1word1
和line1words
的file0
被正确地存储在matrix[0][0][0]
和matrix[0][0][1]
,但在该领域matrix[0][0][2]
即使A[2]
有,也没有line1word3
!
我在做什么呢? 有什么建议吗?
预先非常感谢,欢呼
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]
不是同一项目。 不管数组中的维数如何,元素通常在内存中顺序排列,每一行都在上一行(或可能的列,我想这取决于语言)之后。如果您有一个指针数组,则实际的内容可能在其他地方,但是这些点的排列方式是这样的。 因此,在上面的示例中,必须为编译器提供列数,以便它可以找到成员( 行数可以是可变的。)在三维数组中,必须提供前两个维,以便编译器可以计算项目偏移量。
希望对您有所帮助。
编辑:您可以通过创建自己的函数来处理所有数组项访问来拥有真正的动态数组尺寸。 该功能将需要知道动态尺寸和项目索引,以便可以计算适当的地址。
这看起来是错误的: buffer = (char*) malloc(strlen(line) * sizeof(char));
首先,不需要在C中强制转换malloc。如果没有强制转换就无法编译代码,则可能有两个原因:
int
,或者发生错误。 这可能会导致您的程序行为异常。 为了避免这种情况,请#include <stdlib.h>
。 其次,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<n;j++)
。 您可以使用建议的改进,也可以更改循环: for (j = 0; j <= n; j++)
。 无论哪种方式,您都需要逐个修复。
出于好奇,您正在阅读哪本书?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.