如何从文件复制到数组 [英] How to copy from a file to an array

查看:99
本文介绍了如何从文件复制到数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

#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:

解决方案

You are far better served using line-oriented input to read all lines in a file into a dynamically allocated array. The line-oriented functions available in the standard library are fgetsgetline.

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

如果使用fgets(很好),则必须添加代码以检查每行和realloc short incomplete 读取和strcat该行,直到完成读取为止. getline只是使生活更简单.

您的基本方案是声明 pointer-to-pointer-to-type (即 double-pointer ),分配合理数量的指针来处理文件,如果达到初始限制,请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;
}

我已经放置了一个完整的示例,说明如何将一个文件读入动态分配的2D数组,该数组长于pastbin: C-将文件读入动态分配的2D数组

I have to read an array from a file and the fact i that's the last column is just not being copied. The size of the array and it content is in the file. Here is the code (only the part where the problem is):

#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<stdio.h>
#include<stdlib.h>
#include"encruta1.h"//Just funcion definitions(not used yet)
#define ERRORCOMANDO "ERROR: linea de comandos incorrecta. Utilice:\n" 
#define ERRORCOMAND2 "leelabfich fichero_de_entrada columna_inicio fila_inicio\n"
//Both are error messages

int main(int argc, char *argv[])
{
  char **laberinto;
  char aux;
  int i = 0;//Indice para imprimir la tabla
  int j = 0;//Indice para imprimir la tabla
  int columnas = 0;
  int filas = 0;
  int flag1;//Para saber si fscanf ha funcionado bien
  FILE *fent;

  //Si son cuatro argumentos es correcto
  if(argc == 4)
   {
    //Apertura de archivo
    fent = fopen(argv[1], "r");
    if(fent == NULL)
     fprintf(stderr,"No se puede abrir el fichero de entrada.\n");
    else
    {
     flag1 = fscanf(fent,"%d%d", &columnas, &filas);
     if(flag1 == 2)
     {
      if(filas < 0 || columnas < 0)
       fprintf(stderr,"Las dimensiones han de ser dos numeros enteros.\n");
      else
       {
       //Reserva de memoria   
       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;
          }
        }

      //Pasamos el laberinto del archivo a la tabla

      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;
            else
              laberinto[i][j] = aux;
          }
          }

      for(i = 0; i < filas; i++)
        {
          for(j = 0; j < columnas; j++)
        {//Eliminamos los intentos fallidos
          if(laberinto[i][j] == 'o')//Just ignore the o
            laberinto[i][j] = '.';
          printf("%c", laberinto[i][j]);
        }
          printf("\n");
        }
      //Sustituir por donde se libere memoria abajo
      for(i = 0; i < columnas+1; i++)
        free(laberinto[i]);
      laberinto = NULL;

解决方案

You are far better served using line-oriented input to read all lines in a file into a dynamically allocated array. The line-oriented functions available in the standard library are fgets and getline.

In this case, where you do not know what the maximum number of characters in each line will be, you are better served using getline to read each line as getline will dynamically allocate a line buffer of sufficient size for you.

If you use fgets (which is fine), you would have to add code to check for a short or incomplete read of each line and realloc and strcat the line until a complete read takes place. getline just makes life simpler here.

Your basic scheme is to declare a pointer-to-pointer-to-type (i.e. a double-pointer), allocate a reasonable number of pointers to handle the file, if you reach the initial limit, realloc 2X the number of current pointers and continue.

When done, free the allocated lines, then free the array. A quick example:

#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;
}

Use a memory error checker (like valgrind on Linux) to confirm correct use of the memory and that all memory is properly freed when no longer needed. Look it over and let me know if you have additional questions.

Numeric Array

For numeric arrays, you approach is exactly the same. However, instead of storing the ln in an array of pointers to char, you simply parse the line as required using sscanf or preferrably strtol, etc... The changes required are minimal. e.g.:

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

your read loop then looks like:

/* 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;
    }
}

The helper functions to validate the conversions to long and realloc could be written as:

/* 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;
}

note: you can adjust whether to return NULL or exit on memory exhaustion to fit your needs. For the conversion, you can use simple error checking with strtol as shown below.

/* 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;
}

I have place a full example of how to read a file into a dynamically allocated 2D array of long at pastbin: C - read file into dynamically allocated 2D array

这篇关于如何从文件复制到数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆