Using C, to print out an array from textFile

前端 未结 2 1579
眼角桃花
眼角桃花 2021-01-25 23:02

I\'m trying to create a code, which reads from textile, and then stores the data into memory, prints out to the screen so the user can read it, but it is still saved into the m

相关标签:
2条回答
  • 2021-01-25 23:41
    phrases[i].English = malloc(sizeof(char));
    

    Here the problem lies, you are allocating a single byte and then trying to cram a string into it, which leads to undefined behavior here:

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

    Generally, you should assume a sensible buffer length and read that, and check whether the new line is contained. If that's not the case, read again into another buffer or enlarge the old one (using realloc). Either that or use a non-standard function like getline that does this already for you under the hood.

    Given that your lines are pretty short sentences, a constant buffer size could suffice (let's call it MAX_LINE), which provides us a little easier way to achieve the same:

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

    This reads a string of length MAX_LINE into the buffer buf and terminates before the '\n' is encountered.

    When reading strings, you should refrain from using fscanf("%s", buf) and use fgets() or scanf("%*s", MAX_LINE, ...) instead. This ensures that there will be no attempt to write more data than what you specified, avoiding buffer overflows.

    Edit: The nested loop shouldn't be there. You are basically overwriting phrases[i].TextSpeak a total of phraseCounter times for no benefit. And in the process of that you are leaking a lot of memory.

    0 讨论(0)
  • 2021-01-26 00:05

    There are a number of ways to do this. However, one suggestion I would have would be to make use of line-input tools such as fgets or getline to make reading the file more robust. It is fine to use fscanf for discrete variables (I left it for reading phraseCounter), but for reading string data of unknown length/content, line-input really should be used.

    Below is an example of your code with this employed. The code is commented to explain the logic. The real logic here is the fact that you will read 2-lines for each allocated struct. A simple line counter using % (mod) as a toggle can help you keep track of when to allocate a new struct. I also added code to accept the filename as the first argument to the program. (to run, e.g ./progname <filename>). Let me know if you have questions:

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

    Input

    $ 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
    

    Output

    $ ./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
    

    Verify no memory leaks

    $ 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)
    
    0 讨论(0)
提交回复
热议问题