C语言中,fscanf函数可以读取指向字符数组的指针。

3

我尝试使用fscanf将文件中的行读入到指向字符数组的指针中。但是当我打印时,会出现分段错误。我做错了什么?除了fscanf之外,我应该使用其他函数吗?

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

#define MAXSTACK 100
#define MAXLENGHT 100

void main(int argc, char * argv[]){

  char *filename;
  FILE *fp;
  char *lines[MAXSTACK];
  char * command;
  int top = 0;
  int numlines = 0;

  if(argc < 3){

    fprintf(stderr,"error: Not enough arguments provided\n");
    exit(1);
  }

  filename = argv[1];
  command = argv[2];

  if ( (fp = fopen(filename,"r")) == NULL ){

    fprintf(stderr,"error: Cannot open file %s\n",filename);
    exit(1);
  }
  else{

    for(int i = 0; i < 3; i++){

        fscanf(fp,"%s",lines[i]);
    //    printf("%s\n",lines[i]);
    }

    char **ptr2 = lines;
    for (int i = 0; i < 2; i++){

         printf("%s\n", ptr2[i]);
    }

    if (strcmp(command,"pop")==0){

      //pop(lines);
     }else if (strcmp(command,"print_top")==0){
      //print_top();

    }else if(strcmp(command,"swap_top")==0){

    }
   }
} 

你没有一个字符数组。你有一个指向未确定对象的指针数组。 - David Schwartz
2个回答

3
您可能需要使用fgets来读取文本行:
/* Read a single line into a temporary buffer */
char lineBuffer[MAX_LINE_LENGTH];
while (fgets(lineBuffer, sizeof(lineBuffer), fp) != NULL) {
    /* Process the read line */
}

一旦你已经在临时缓冲区读取了一行,你可以使用malloc(或者你可以使用strdup)将读取的字符串进行深度复制到你在堆上分配的一些内存中,然后你可以将指向该内存的指针存储到你的lines数组中:

 /* Inside the body of the while loop */

 /* 
  * Deep copy current line into the string pointer array.
  * strdup = malloc + strcpy
  * Note that free is required to release memory!
  */
 lines[currLineIndex] = strdup(lineBuffer);

 currLineIndex++;

请注意,当您编写如下代码时:
char *lines[MAXSTACK];
你正在栈上分配一个由MAXSTACK项组成的数组,每个项都是一个char*指针。但是你必须给这些指针赋予一些有意义的值(例如:从堆中分配一些内存并指向该内存)。
当然,完成后,你必须扫描整个数组并调用free释放每个元素指针,以避免内存泄漏。
此外,一个好的编程习惯是在使用数组之前清除数组中的指针,例如:
memset(lines, 0, sizeof(lines));

1
fscanf("%s", lines[i]) 会读取一系列非空白字符(注意,不是整行)到指向 lines[i] 的内存中。问题在于,您没有设置 lines[i] 指向任何内存,这就是为什么会出现段错误的原因,因为您要求将一系列字符复制到未定义的位置。
如果您用字符数组的数组声明替换您的字符指针数组声明 char *lines[MAXSTACK];,使用 char lines[MAXLENGTH][MAXSTACK] 声明一个字符数组的数组,那么 lines[i] 就是一个由 MAXLENGTH 个字符组成的数组,fscanf("%s", lines[i]) 就可以在没有段错误的情况下进行复制。
现在问题是,如果 fscanf 尝试读取的字符串比 MAXLENGTH 更长会发生什么?答案是会读取比可以适应 lines[MAXLENGTH] 数组更多的字符,这就是所谓的缓冲区溢出。为了防止这种情况,您可以限制 fscanf 从字符串中读取的最大字符数,例如限制为 100 个字符,使用 fscanf("%100s", lines[i])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接