【问题标题】:Using C, to print out an array from textFile使用 C,从文本文件中打印出一个数组
【发布时间】:2015-06-04 04:07:36
【问题描述】:

我正在尝试创建一个代码,该代码从纺织品中读取数据,然后将数据存储到内存中,打印到屏幕上以便用户阅读,但它仍然保存在内存中以便您可以使用它对于程序的其余部分..

这是纺织品的样品

            75
            nevermind
            nvm
            not much
            nm
            no problem
            np
            people
            ppl
            talk to you later
            ttyl
            because
            cuz
            i don't know
            idk
            as soon as possible
            asap
            yeah
            ya
            how are you
            hru
            you

列表继续,如果包括第一个数字,它总共有 150 个单词,151 行。 75 用于告诉您有多少对。

无论如何,这是我到目前为止编写的代码,它使用了这个结构

            typedef struct
            {
                char *English;
                char *TextSpeak;
            }Pair;

目前我写的代码是:

                FILE *infile =fopen("dictionary.txt","r");

                int phraseCounter;
                fscanf(infile, "%i", &phraseCounter); //Now you have the number of phrase pairs

                //Allocate memory
                Pair *phrases=malloc(sizeof(Pair) * phraseCounter);

                //Run loop
                for(int i=0; i < phraseCounter; i++){
                    //Get the english word
                    phrases[i].English = malloc(sizeof(char));
                    fscanf(infile,"%s",phrases[i].English);

                    //run loop to read next line
                    for(int a=0; a < phraseCounter; a++){
                        phrases[i].TextSpeak = malloc(sizeof(char));
                        fscanf(infile,"%s",phrases[i].TextSpeak);
                    }
                    printf("%s - %s\n", phrases[i].English, phrases[i].TextSpeak);

                }

                fclose(infile);

                for(int i=0; i < phraseCounter; i++)
                    free(phrases[i].English);


                free(phrases);

我不断得到的输出是:

            nevermind - atm
            by - definitely
            def - 
            - 
            - 
            - 
            - 
            - 

它一直持续到 75 行。

现在我不确定是否应该使用二维数组,或者这是否可以接受。任何帮助将不胜感激!谢谢

【问题讨论】:

  • phrases[i].English = malloc(sizeof(char));,你能解释一下你认为这是做什么的吗?
  • 为变量分配足够的内存?
  • 这总是分配一个字节。
  • 您找到问题的答案了吗?如果是这样,您应该考虑将最适合您的答案标记为已接受。

标签: c arrays memory file-io struct


【解决方案1】:

有很多方法可以做到这一点。但是,我的一个建议是使用line-input 工具,例如fgetsgetline,以使读取文件更加健壮。对离散变量使用fscanf 很好(我把它留给阅读phraseCounter),但对于读取长度/内容未知的字符串数据,确实应该使用行输入。

以下是您的代码示例。代码被注释以解释逻辑。这里真正的逻辑是您将为每个分配的结构读取 2 行。使用% (mod) 作为切换的简单行计数器可以帮助您跟踪何时分配新结构。我还添加了代码来接受文件名作为程序的第一个参数。 (运行,例如./progname &lt;filename&gt;)。如果您有任何问题,请告诉我:

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

#define MAXL 128

typedef struct Pair
{
    char *English;
    char *TextSpeak;

} Pair;

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

    if (argc < 2) {
        fprintf (stderr, "error: insufficient input. Usage: %s filename\n", argv[0]);
        return 1;
    }

    Pair **pair = NULL;             /* pointer to array of pointers */
    char line[MAXL] = {0};          /* variable to hold line read   */
    FILE* infile = NULL;            /* file pointer for infile      */
    unsigned int phraseCounter = 0; /* count of pairs               */
    unsigned int index = 0;         /* index to pairs read          */
    size_t nchr = 0;                /* length of line read          */
    size_t lnum = 0;                /* line number read             */

    /* open file and validate */
    if (!(infile = fopen ((argv[1]), "r"))) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    /* read phraseCounter */
    if (!fscanf (infile, "%u%*c", &phraseCounter)) {
        fprintf (stderr, "error: failed to read phraseCounter.\n");
        return 1;
    }

    /* allocate phraseCounter number of pointers to Pair */
    if (!(pair = calloc (phraseCounter, sizeof *pair))) {
        fprintf (stderr, "error: memory allocation failed.\n");
        return 1;
    }

    /* read each line in file */
    while (fgets (line, MAXL - 1, infile) != NULL)
    {
        nchr = strlen (line);       /* get the length of line           */

        if (nchr < 1)               /* if blank or short line, skip     */
            continue;

        if (line[nchr-1] == '\n')   /* strip newline from end           */
            line[--nchr] = 0;

        if (lnum % 2 == 0)          /* even/odd test for pair index     */
        {
            /* allocate space for pair[index]   */
            if (!(pair[index] = calloc (1, sizeof **pair))) {
                fprintf (stderr, "error: memory allocation failed for pair[%u].\n", index);
                return 1;
            }
            pair[index]-> English = strdup (line);  /* allocate space/copy to English   */
        }
        else
        {
            pair[index]-> TextSpeak = strdup (line);/* allocate space/copy to TextSpeak */
            index++;    /* only update index after TextSpeak read   */
        }

        lnum++;     /* increment line number    */
    }

    if (infile) fclose (infile);            /* close file pointer after read    */

    /* print the pairs  */
    printf ("\n Struct     English                   TextSpeak\n\n");
    for (nchr = 0; nchr < index; nchr++)
        printf (" pair[%3zu]  %-24s  %s\n", nchr, pair[nchr]-> English, pair[nchr]-> TextSpeak);

    /* free memory allocated to pair */
    for (nchr = 0; nchr < index; nchr++)
    {
        if (pair[nchr]-> English) free (pair[nchr]-> English);
        if (pair[nchr]-> TextSpeak) free (pair[nchr]-> TextSpeak);
        if (pair[nchr]) free (pair[nchr]);
    }
    if (pair) free (pair);

    return 0;
}

输入

$ cat dat/pairs.txt
10
nevermind
nvm
not much
nm
no problem
np
people
ppl
talk to you later
ttyl
because
cuz
i don't know
idk
as soon as possible
asap
yeah
ya
how are you
hru

输出

$ ./bin/struct_rd_pairs dat/pairs.txt

 Struct     English                   TextSpeak

 pair[  0]  nevermind                 nvm
 pair[  1]  not much                  nm
 pair[  2]  no problem                np
 pair[  3]  people                    ppl
 pair[  4]  talk to you later         ttyl
 pair[  5]  because                   cuz
 pair[  6]  i don't know              idk
 pair[  7]  as soon as possible       asap
 pair[  8]  yeah                      ya
 pair[  9]  how are you               hru

验证没有内存泄漏

$ valgrind ./bin/struct_rd_pairs dat/pairs.txt
==3562== Memcheck, a memory error detector
==3562== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==3562== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==3562== Command: ./bin/struct_rd_pairs dat/pairs.txt
==3562==
<snip>
==3562==
==3562== HEAP SUMMARY:
==3562==     in use at exit: 0 bytes in 0 blocks
==3562==   total heap usage: 32 allocs, 32 frees, 960 bytes allocated
==3562==
==3562== All heap blocks were freed -- no leaks are possible
==3562==
==3562== For counts of detected and suppressed errors, rerun with: -v
==3562== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

【讨论】:

    【解决方案2】:
    phrases[i].English = malloc(sizeof(char));
    

    问题出在此处,您正在分配一个字节,然后尝试将字符串塞入其中,这会导致此处出现未定义的行为:

    fscanf(infile,"%s", phrases[i].English);
    

    通常,您应该假设一个合理的缓冲区长度并读取它,并检查是否包含新行。如果不是这种情况,请再次读入另一个缓冲区或扩大旧缓冲区(使用realloc)。 或者使用像 getline 这样的非标准函数,它已经在后台为您完成了这项工作。

    鉴于您的行是非常短的句子,一个恒定的缓冲区大小就足够了(我们称之为MAX_LINE),这为我们提供了一种更简单的方法来实现同样的目标:

    fscanf(infile, "%*[^\n]s", MAX_LINE, buf);
    

    这会将长度为MAX_LINE 的字符串读入缓冲区buf 并在遇到'\n' 之前终止。

    读取字符串时,应避免使用fscanf("%s", buf),而应使用fgets()scanf("%*s", MAX_LINE, ...)。这样可以确保不会尝试写入比您指定的更多的数据,从而避免缓冲区溢出。

    编辑:嵌套循环不应该存在。你基本上覆盖phrases[i].TextSpeak 总共phraseCounter 次,没有任何好处。在此过程中,您会泄漏大量内存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多