文件到字符串数组(逐行)

时间:2014-05-10 14:28:47

标签: c arrays string file c-strings

我有文本文件,我想将每一行保存到字符串数组(全局定义为fileA)。我所知道的是文件中的所有行都短于101个字符。我做了3个功能:

  • char * lineToString(char * filename, int line) - 返回所选行的值
  • int getLineCount(char * filename) - 返回文件中的行数(计数形式1)
  • char * fileToArray(char * filename) - 返回字符串数组

我认为这些功能可以正常工作,问题出现在main()中。我打印sizeof(...)只是为了调试。我的代码中还有很多警告,我该如何修复它们?

谢谢!

代码:


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

int MAX_LINES = 1000;       //0 <= x && x < 1000
int MAX_ROW_LENGTH = 101;   //100 + 1 ('\0')
char * fileA = NULL;


char * lineToString(char * filename, int line){
    FILE * file = fopen(filename, "r");
    int currLine = 1;
    int currCol = 0;
    char currChar;
    char * string = (char *) malloc(sizeof(char)*MAX_ROW_LENGTH);
    string[0] = '\0';
    if(file != NULL && line >= 1){
        while((currChar = getc(file)) != EOF){
            if(currLine == line){
                if(currChar == '\n'){
                    string[currCol] = '\0';
                    break;
                }else{
                    string[currCol] = currChar;
                    currCol++;
                }
            }

            if(currChar == '\n') currLine++;
        }
        fclose(file);
    }
    return string;
}

int getLineCount(char * filename){
    FILE * file = fopen(filename, "r");
    int count = 0;
    char c;
    if(file != NULL){
        while((c = getc(file)) != EOF)
            if(c == '\n') count++;  
        fclose(file);
    }   
    return count;
}

char * fileToArray(char * filename){
    int i;
    int lineCount = getLineCount(filename);
    char array[lineCount][MAX_ROW_LENGTH];
    for(i = 1; i <= lineCount; i++){
        strcpy(array[i], lineToString(filename, i));
        //printf("%s\n", array[i]);
    }
    printf("%d\n",sizeof(array));
    return array;
}

int main(int argc, char **argv){

    fileA = (char *) malloc(sizeof(fileToArray(argv[1])));
    strcpy(fileA, fileToArray(argv[1]));
    printf("%d\n", (int) sizeof(fileA));
    int i;
    for(i = 0; i < (int) sizeof(fileA); i++){
        printf("%s\n", fileA[i]);
    }
    return 0;
}

控制台:

matjazmav:~/FRI13_14/SE02/P2/DN/DN08$ gcc 63130148-08.c -o 63130148-08
63130148-08.c: In function ‘fileToArray’:
63130148-08.c:58:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat]
63130148-08.c:59:2: warning: return from incompatible pointer type [enabled by default]
63130148-08.c:59:2: warning: function returns address of local variable [enabled by default]
63130148-08.c: In function ‘main’:
63130148-08.c:69:3: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat]
matjazmav:~/FRI13_14/SE02/P2/DN/DN08$ ./63130148-08 input-1a input-1b
808
8
Segmentation fault (core dumped)

2 个答案:

答案 0 :(得分:2)

您应该考虑使用标准库中的例程。

我尝试使用标准库中的函数,而不是编写我自己的等价物,除非绝对必要。库中的函数几乎肯定比我写的任何东西都要好 - 除非我从事为标准库编写代码的工作。

我对C有点生疏,今天我的偏好是C ++和C#。很抱歉,如果下面的伪代码中存在一些语法错误。

为每次读取一行打开和关闭文件的效率非常低。

以下是一些感兴趣的功能

getline - 请参阅How to explain the parameters of getline() in C - 是此类任务的主力军。它将自动为线路分配足够的存储空间。

快退 - 请参阅http://www.tutorialspoint.com/c_standard_library/c_function_rewind.htm

feof - 检测流上的文件结尾,请参阅http://www.tutorialspoint.com/c_standard_library/c_function_feof.htm

伪代码 - 未经测试:

FILE fileHandle;
fileHandle = fopen(filename, "r");

if (! fileHandle) yourErrorExit();

// Count the lines -- there may be a system call that will do this more efficiently
int fileLengthInLines = 0;
char *lineBuffer = (char*)malloc(sizeOf(char) * maximumSizeOfLine]);
int bytesRead;

while (! feof(fileHandle)) {
int err;
err = getline(&lineBuffer, &bytesRead, filehandle) // ignore the string returned
if (!err) ; // process error appropriately
fileLengthInLines ++;  // this gives you your length of file in lines
}
free(lineBuffer); // we won't use it again

// allocate your array
char **stringArray;
stringArray = (char**) malloc(sizeof(char*)*fileLengthInLines);  

rewind(fileHandle); // get back to start of file

// Read lines and store
int lineNumber = 0;
char *getlineBuffer = NULL; // to force getline to allocate
int lineLength;
while (! feof(fileHandle)) {
   if (! (lineLength = getline(&getLineBuffer, 0, fileHandle))) ; // process error
   stringArray[lineNumber] = getLineBuffer;
   getLineBuffer = NULL; // to force getline to allocate on next iteration
   lineNumber++;

}

fclose(fileHandle);

// Check that all lines are processed -- compare fileLengthInLines with lineNumber
// Be sure to deallocate stringArray and its strings when you are done

答案 1 :(得分:1)

我看到的一个问题是你需要移动线

        if(currChar == '\n') currLine++;

在while循环中。

当我使用成熟的电脑而不是平板电脑时,我会看到一些我能够描述的问题。

<强>更新

你有

char * fileToArray(char * filename){
    int i;
    int lineCount = getLineCount(filename);
    char array[lineCount][MAX_ROW_LENGTH];
    for(i = 1; i <= lineCount; i++){
        strcpy(array[i], lineToString(filename, i));
        //printf("%s\n", array[i]);
    }
    printf("%zu\n",sizeof(array));
    return array;
}

此功能存在问题:

  1. char*的返回值与return语句return array;不兼容。 array可以视为char (*)[MAX_ROW_LENTH],但不能视为char*

  2. 即使返回类型和返回语句匹配,主要问题是您尝试返回指向将在函数返回时删除的对象的指针。指针在调用函数中无效。

  3. 该行

        strcpy(array[i], lineToString(filename, i));
    

    应该是

        strcpy(array[i-1], lineToString(filename, i));
    

    因为C中的数组索引以0开头,而不是1

  4. 其他问题:

    1. 您正在为string中的lineToString分配内存,但您尚未取消分配。

    2. 您正在为fileA中的main分配内存,但您尚未取消分配。

    3. 以下版本的fileToArraymain适用于我的测试。我尽可能地保留你的代码并修改我认为绝对必要的代码。

      void fileToArray(char * filename, int lineCount, char (*array)[MAX_ROW_LENGTH])
      {
          int i;
          char* string;
          for(i = 1; i <= lineCount; i++){
              string = lineToString(filename, i);
              strcpy(array[i-1], string);
              free(string);
          }
      }
      
      int main(int argc, char **argv)
      {
          int i;
          int lineCount = getLineCount(argv[1]);
          char array[lineCount][MAX_ROW_LENGTH];
          fileToArray(argv[1], lineCount, array);
          for(i = 0; i < lineCount; i++){
              printf("%s\n", array[i]);
          }
          return 0;
      }
      

      PS James R Matey在回答中的评论非常有效。打开和关闭文件只是为了获得一行文本是昂贵的。我希望你能找到一种方法将他的建议纳入你的代码中。