使用C,从文本文件中打印出一个数组

时间:2015-03-30 23:31:51

标签: c arrays memory file-io struct

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

以下是纺织品的样本

            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行。

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

2 个答案:

答案 0 :(得分:0)

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次没有任何好处。在这个过程中你会泄漏很多记忆。

答案 1 :(得分:0)

有很多方法可以做到这一点。但是,我建议的一个建议是使用line-inputfgetsgetline工具来使文件读取更加健壮。可以将fscanf用于离散变量(我将其保留为读取phraseCounter),但是为了读取未知长度/内容的字符串数据,应该使用行输入。

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

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