【问题标题】:How to copy from a file to an array如何从文件复制到数组
【发布时间】:2016-01-09 01:00:23
【问题描述】:

我必须从一个文件中读取一个数组,而事实上 i 是最后一列并没有被复制。数组的大小及其内容在文件中。这是代码(仅是问题所在的部分):

#include<stdio.h>
#include<stdlib>
int main(int argc, char * argv[]){ 
char **laberinto;
char aux;
fent = fopen(argv[1], "r");
if
 fprintf(stderr,"Couldn't open.\n");
else
{
 laberinto = (char **) calloc(columnas, sizeof(char *));
 for (i = 0; (NULL != laberinto) && (i < columnas); i++)
  {
      laberinto[i] = (char *) calloc(filas, sizeof(char));
      if (NULL == laberinto[i])
       {
        for ( j = i - 1; j >= 0; j-- )
          free(laberinto[j]); 
        free(laberinto);
        laberinto = NULL;
       }
  }
 for(i = 0, j = 0; i < filas+1; i++)
    for(j = 0; j < columnas+1; j++)
      {
        if(!feof(fent))
          {
            aux = fgetc(fent);
            if(aux == '\n')
            aux = 0;
           }}

Edit 1(full code) it generates a core by the way:

#include
#include
#include"encruta1.h"//只是函数定义(尚未使用)
#define ERRORCOMANDO "错误:不正确的命令线。Utilice:\n"
#define ERRORCOMAND2 "leelabfich fichero_de_entrada columna_inicio fila_inicio\n"
//都是错误信息

int main(int argc, char *argv[])
{
  char **laberinto;
  字符辅助;
  int i = 0;//indice para imprimir la tabla
  int j = 0;//indice para imprimir la tabla
  整数列 = 0;
  int filas = 0;
  int flag1;//Para saber si fscanf ha funcionado bien
  文件 *fent;

  //Si son cuatro argumentos es correcto
  如果(argc == 4)
   {
    //Apertura de 档案馆
    fent = fopen(argv[1], "r");
    如果(芬== NULL)
     fprintf(stderr,"No se puede abrir el fichero de entrada.\n");
    别的
    {
     flag1 = fscanf(fent,"%d%d", &columnas, &filas);
     如果(标志1 == 2)
     {
      if(filas = 0; j-- )
          免费(laberinto [j]);
        免费(laberinto);
        laberinto = NULL;
          }
        }

      //Pasamos el laberinto del archivo a la tabla

      for(i = 0, j = 0; i 

【问题讨论】:

  • 您的代码示例无法编译。这是您一直在使用的实际代码吗? fent, columnas, i, filas, j, ... 都是未定义的。最好知道文件格式/内容是什么。
  • 不,它只是一个简短的版本。我将编辑以放置完整的代码
  • 请只使用与编译相关的部分并说明您的问题。 sscce
  • 不要将calloc() 转换为char **,这没有必要。
  • 抱歉第一次发帖。我现在已经花了大约一个小时来寻找和思考解决方案

标签: c arrays file


【解决方案1】:

使用面向行的输入将文件中的所有行读入动态分配的数组中会更好。标准库中可用的面向行的 函数是fgetsgetline

在这种情况下,如果您不知道每行中的最大字符数是多少,则最好使用getline 来读取每一行,因为getline 将动态分配足够大小的行缓冲区以供你。

如果您使用fgets(这很好),您必须添加代码来检查每一行的shortincomplete 读取和reallocstrcat 直到完成读取。 getline 让生活更简单。

你的基本方案是声明一个pointer-to-pointer-to-type(即一个双指针),分配合理数量的指针来处理文件,如果达到初始限制,realloc 2X 当前指针的数量并继续。

完成后,释放分配的行,然后释放数组。一个简单的例子:

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

#define NMAX 128    /* initial number of pointers */

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

    char **array = NULL;            /* array to hold lines read         */
    char *ln = NULL;                /* NULL forces getline to allocate  */
    size_t n = 0;                   /* initial ln size, getline decides */
    ssize_t nchr = 0;               /* number of chars actually read    */
    size_t idx = 0;                 /* array index counter              */
    size_t nmax = NMAX;             /* check for reallocation           */
    size_t i = 0;                   /* general loop variable            */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; /* open stream  */

    if (!fp)  {       /* validate stream open for reading */
        fprintf (stderr, "error: file open failed '%s',\n", argv[1]);
        return 1;
    }

    /* allocate NMAX pointers to char* */
    if (!(array = calloc (NMAX, sizeof *array))) {
        fprintf (stderr, "error: memory allocation failed.");
        return 1;
    }

    /* read each line from fp  */
    while ((nchr = getline (&ln, &n, fp)) != -1)
    {
        /* strip newline or carriage rtn    */
        while (nchr && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
            ln[--nchr] = 0;

        array[idx++] = strdup (ln); /* allocate/copy ln to array        */

        if (idx == nmax) {          /* if idx reaches nmax, reallocate  */
            char **tmp = realloc (array, nmax * 2 * sizeof *tmp);
            if (!tmp) {
                fprintf (stderr, "error: memory exhausted.\n");
                break;
            }
            array = tmp;    /* set new pointers NULL */
            memset (array + nmax, 0, nmax * sizeof tmp);
            nmax *= 2;
        }
    }

    if (ln) free (ln);              /* free memory allocated by getline */
    if (fp != stdin) fclose (fp);   /* close open file if not default   */

    /* print array */
    printf ("\n lines read from '%s'\n\n", argc > 1 ? argv[1] : "stdin");
    for (i = 0; i < idx; i++)
        printf ("   line[%3zu]  %s\n", i, array[i]);

    for (i = 0; i < idx; i++)
        free (array[i]);    /* free each line */
    free (array);           /* free pointers  */

    return 0;
}

使用内存错误检查器(如 Linux 上的 valgrind)来确认内存的正确使用以及所有内存在不再需要时是否已正确释放。仔细查看,如果您还有其他问题,请告诉我。

数值数组

对于数值数组,你的方法是完全一样的。但是,您无需将ln 存储在指向char 的指针数组中,而是根据需要使用sscanf 或最好使用strtol 等来解析行...所需的更改很少。例如:

...
#include <limits.h>
#include <errno.h>
...
long *array = NULL;             /* pointer to long                  */
int base = argc > 2 ? atoi (argv[2]) : 10; /* base (default: 10)    */
...

您的读取循环如下所示:

/* read each line from file - separate into array       */
while ((nchr = getline (&ln, &n, fp)) != -1)
{
    char *p = ln;      /* pointer to ln read by getline */
    char *ep = NULL;   /* endpointer for strtol         */

    while (errno == 0)
    {   /* parse/convert each number in line into array */
        array[idx++] = xstrtol (p, &ep, base);

        if (idx == nmax)        /* check NMAX / realloc */
            array = realloc_long (array, &nmax);

        /* skip delimiters/move pointer to next digit   */
        while (*ep && *ep != '-' && (*ep < '0' || *ep > '9')) ep++;
        if (*ep)
            p = ep;
        else
            break;
    }
}

验证转换为longrealloc 的辅助函数可以写成:

/* reallocate long pointer memory */
long *realloc_long (long *lp, unsigned long *n)
{
    long *tmp = realloc (lp, 2 * *n * sizeof *lp);
    if (!tmp) {
        fprintf (stderr, "%s() error: reallocation failed.\n", __func__);
        // return NULL;
        exit (EXIT_FAILURE);
    }
    lp = tmp;
    memset (lp + *n, 0, *n * sizeof *lp); /* memset new ptrs 0 */
    *n *= 2;

    return lp;
}

注意:您可以调整是否在内存耗尽时返回NULLexit 以满足您的需求。对于转换,您可以使用strtol 进行简单的错误检查,如下所示。

/* simple strtol wrapper with error checking */
long xstrtol (char *p, char **ep, int base)
{
    errno = 0;

    long tmp = strtol (p, ep, base);

    /* Check for various possible errors */
    if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
        (errno != 0 && tmp == 0)) {
        perror ("strtol");
        exit (EXIT_FAILURE);
    }

    if (*ep == p) {
        fprintf (stderr, "No digits were found\n");
        exit (EXIT_FAILURE);
    }

    return tmp;
}

我已经放置了一个完整的示例,说明如何将文件读入 Pastbin 中动态分配的 long 二维数组:C - read file into dynamically allocated 2D array

【讨论】:

    猜你喜欢
    • 2016-10-01
    • 2016-03-07
    • 2019-02-19
    • 1970-01-01
    • 2020-01-24
    • 2014-03-04
    • 1970-01-01
    • 2019-03-03
    • 1970-01-01
    相关资源
    最近更新 更多