如何从文件复制到数组 [英] How to copy from a file to an array
问题描述
我必须从文件中读取一个数组,而事实上我是最后一列,只是没有被复制.数组的大小及其内容在文件中.这是代码(仅是问题所在的部分):
#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 fgets
和getline
.
在这种情况下,如果您不知道每一行的最大字符数,最好使用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;
}
}
用于验证转换为long
和realloc
的辅助函数可以写为:
/* 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;
}
注意:您可以调整是否在内存耗尽时返回NULL
或exit
以满足您的需要.对于转换,可以使用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屋!