返回从文件读取的数字数组

时间:2019-04-30 20:54:05

标签: c

我有一个作业,其中我需要编写一个函数,该函数将从文件中读取数字到数组并返回该数组(指向第一个元素的指针)。 我写了一个从文件读到数组的函数,但我不知道如何返回它。

void to_array(FILE* file, int bufsize){
char arr[bufsize][100];
fseek(file, 0, SEEK_SET);
int i = 0;
while(!feof(file)){
    fscanf(file, "%s", arr[i]);
    i++;
}

我将不胜感激。

3 个答案:

答案 0 :(得分:2)

void to_array(FILE* file, int bufsize){
  char arr[bufsize][100];
  ...
}

您的数组是本地数组,如果您返回其地址,它将无法使用

一种通过 malloc 在头部分配它的方法,另一种是在参数中接收该数组以填充它。请注意,如果没有恒定的大小,它就不能是静态的

请勿使用 feof 检查 fscanf

的结果

您阅读数字,因此该数组必须是数字数组,请考虑 int

函数接收文件描述符和指向将包含放置到数组中的元素数量的变量的指针的示例,函数将根据需要返回分配在堆中的数组

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

int * to_array(FILE * fp, size_t * sz)
{
  int * a = malloc(0); /* initially empty */
  int v;

  *sz = 0; /* initially no element */

  while (fscanf(fp, "%d", &v) == 1) {
    a = realloc(a, (++*sz)*sizeof(int)); /* add an entry */
    a[*sz - 1] = v; /* set entry */
  }

  return a;
}

int main()
{
  size_t sz;
  int * a = to_array(stdin, &sz);

  /* check */
  for (size_t i = 0; i != sz; ++i)
    printf("%d\n", a[i]);

  /* free used memory */
  free(a);

  return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall a.c
pi@raspberrypi:/tmp $ echo 11 22 33 | ./a.out
11
22
33
pi@raspberrypi:/tmp $

valgrind 下执行:

pi@raspberrypi:/tmp $ echo 11 22 33 | valgrind ./a.out
==10080== Memcheck, a memory error detector
==10080== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10080== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10080== Command: ./a.out
==10080== 
11
22
33
==10080== 
==10080== HEAP SUMMARY:
==10080==     in use at exit: 0 bytes in 0 blocks
==10080==   total heap usage: 6 allocs, 6 frees, 5,144 bytes allocated
==10080== 
==10080== All heap blocks were freed -- no leaks are possible
==10080== 
==10080== For counts of detected and suppressed errors, rerun with: -v
==10080== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

该函数每次都分配一个附加条目,可以按给定数量的条目的块进行操作,而不必在每次必须添加条目时都这样做。

答案 1 :(得分:0)

使用时请确保#include <stdio.h>

通常,用户的特权是他们想要文件指针的位置,也就是说,您不需要fseek

一个人必须接受缓冲区大小以及缓冲区大小,否则一个人可以使用动态realloc(更复杂的错误报告和free。)

使用返回值决定是否继续,而不是feof。我认为您已经使用fscanf选择了正确的输入读取功能;请务必阅读documentation。具体来说,%s几乎不是您想要的。也许%d

while存在缓冲区溢出的风险;如果您有固定大小的缓冲区,则如下所示:

size_t i;
for(i = 0; i < bufsize && scanf("%d", buf + i) == 1; i++);

可能会发生几件事,包括:

  • 流(文件)错误。使用ferror进行测试。
  • 您没有找到文件的末尾,适合使用feof进行测试;如果i == bufsize程序没有更多的空间来容纳数字;否则,它是无效数字。这些条件很难处理,但我建议使用errno
  • 成功。

也许有人想返回一个布尔值以获取成功?

答案 2 :(得分:0)

如果您选择使用具有自动存储期限的数组,则必须在调用函数中声明该数组,并将指向该数组的指针传递给您的函数。然后,您可以在函数中填充数组。但是,您还必须提供一种返回读取的字符串数的方法。您为函数选择的void类型使此操作变得复杂(有一点复杂),因为您通常会选择有意义的返回类型,例如size_t,从而允许您返回读取的字符串数。尽管如此,您仍可以传递指向size_t值的指针,并在函数中更新该地址处的值,从而使调用函数中可以使用的字符串数变回原来的值。

一些注意事项:

/* if you need a constant, #define one (or more) */
#define STRSZ  32       /* maximum string stize in array */
#define NSTR  100       /* maximum number of strings in array */

不要忽略缓冲区大小)未删节词典中的最长单词(非医学)为29个字符,最长的64位数字为20个字符(包括符号) ,因此对于正常使用,30的缓冲区大小就足够了,32将解决所有结尾的标点符号。 (如果不需要考虑空格,则需要将STRSZ64加倍。)根据需要调整字符串数和每个字符串中的最大字符数。

然后可以编写函数以将指针带到char [32]数组,例如

 void to_array (char (*arr)[STRSZ], FILE *fp, size_t *nstr)
{
    *nstr = 0;  /* initialize number of strings to zero */

    /* protect array bounds while reading each string from file */
    while (*nstr < NSTR && fscanf (fp, "%31s" , arr[*nstr]) != EOF)
        (*nstr)++;  /* increment number of strings */
}

注意:使用 field-width 修饰符"%31s"来保护每个字符串从文件中读取时的边界,以及*nstr < NSTR保护数组边界以保护从文件中读取的字符串的数量)

main()中,您可以简单地声明一个具有自动存储持续时间的2D数组和一个变量,以跟踪填充的字符串数,例如

    char arr[NSTR][STRSZ] = {{0}};  /* array to hold strings (max 31 char) */
    size_t n = 0;                   /* number of strings read */

现在,您可以按以下方式调用to_array()函数:

    to_array (arr, fp, &n);     /* read strings from file, n holds number */

在调用to_array()之前,将其与正确的验证一起放到可以打开文件的状态下,可以这样做:

#include <stdio.h>

/* if you need a constant, #define one (or more) */
#define STRSZ  32       /* maximum string size */
#define NSTR  100       /* maximum number of strings in array */

void to_array (char (*arr)[STRSZ], FILE *fp, size_t *nstr)
{
    *nstr = 0;  /* initialize number of strings to zero */

    /* protect array bounds while reading each string from file */
    while (*nstr < NSTR && fscanf (fp, "%31s" , arr[*nstr]) != EOF)
        (*nstr)++;  /* increment number of strings */
}

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

    char arr[NSTR][STRSZ] = {{0}};  /* array to hold strings (max 31 char) */
    size_t n = 0;                   /* number of strings read */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    to_array (arr, fp, &n);     /* read strings from file, n holds number */

    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    for (size_t i = 0; i < n; i++)  /* output each string in arr */
        printf ("arr[%2zu] : '%s'\n", i, arr[i]);
}

示例输入文件

$ cat ../dat/10int_nl.txt
8572
-2213
6434
16330
3034
12346
4855
16985
11250
1495

使用/输出示例

$ ./bin/fscanffile ../dat/10int_nl.txt
arr[ 0] : '8572'
arr[ 1] : '-2213'
arr[ 2] : '6434'
arr[ 3] : '16330'
arr[ 4] : '3034'
arr[ 5] : '12346'
arr[ 6] : '4855'
arr[ 7] : '16985'
arr[ 8] : '11250'
arr[ 9] : '1495'

仔细检查一下,如果还有其他问题,请告诉我。如果您需要一次阅读一行,请考虑使用fgets()