Thread: Segmentation Fault building array of strings from input record

  1. #1
    Registered User
    Join Date
    Dec 2015
    Location
    North-Central Indiana
    Posts
    17

    Segmentation Fault building array of strings from input record

    I'm trying to build an array of strings from an input record. I'm getting a segmentation fault. Here's my code. The segmentation fault occurs on line 28, "strcopy..."

    Suggestions? Thanks!

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <stdbool.h>
    #include <ctype.h>
    
    /* Windows filenames */
    #define xtni_filename "In_Transactions.ofx" /* OFX */
    #define xtni_line_len 55
    FILE *xtni;
    bool sw_xtni_eof = false;
    
    char *get_xtni(int xtni_words_max, char xtni_words[])
    {
        char line_xtni_cur[xtni_line_len];
        if (fgets(line_xtni_cur, xtni_line_len, xtni) == NULL) {
            sw_xtni_eof = true;
            return xtni_words;
        }
    
        char * xtni_cur_word;
        int xtni_num_words = 0;
        xtni_cur_word = line_xtni_cur;
        printf("line_xtni_cur: %s\n", line_xtni_cur); // testing
        xtni_cur_word = strtok (xtni_cur_word," "); // first word
        while (xtni_cur_word != NULL) {
            strcpy(&xtni_words[xtni_num_words], xtni_cur_word);
            xtni_cur_word = strtok (NULL," "); // next word
            xtni_num_words++;
            }
    
        return xtni_words;
    }
    
    int main()
    {
       xtni=fopen(xtni_filename, "r");
       int xtni_words_max = 12;
       char * xtni_words[xtni_words_max];
       while (sw_xtni_eof == false) {
          char *xtni_words = get_xtni(xtni_words_max, xtni_words);
       }
    
       printf(xtni_words[0]);  // testing
       return 0;
    
    }

  2. #2
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    I'm not having a good week, lol.

    My *guess* is that xtni_line_len is not large enough.


    Last edited by Hodor; 12-21-2015 at 07:28 AM.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,663
    You don't allocate any space to store each string.
    p[i] = malloc(strlen(s)+1);
    strcpy(p[i],s);

    And you don't get an error message because your inner declaration of xtni_words hides the real one.
    Code:
    $ gcc -Wshadow -Wall -std=c99 foo.c
    foo.c: In function ‘main’:
    foo.c:42:11: warning: declaration of ‘xtni_words’ shadows a previous local [-Wshadow]
    foo.c:40:10: warning: shadowed declaration is here [-Wshadow]
    foo.c:45:3: warning: format not a string literal and no format arguments [-Wformat-security]
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    You should compile at a high warning level and pay attention to warnings. For example, my compiler warned me about your code:
    Code:
    test.c: In function ‘main’:
    test.c:45:4: warning: format not a string literal and no format arguments [-Wformat-security]
        printf(xtni_words[0]);  // testing
        ^
    Thankfully, this is easily fixed, e.g.,
    Code:
    printf("%s", xtni_words[0]);
    Other things to note:
    • As a common convention, macro names should be fully uppercase, e.g., XTNI_FILENAME instead of xtni_filename.
    • You should avoid global variables as they tend to make it harder to reason about (and hence debug) your program. For so trivial a program as this, you might not feel the negative effects, but when you have large and complex programs, you would fare better having avoided them. For your program, I would suggest changing this:
      Code:
      char *get_xtni(int xtni_words_max, char xtni_words[])
      to:
      Code:
      char *get_xtni(FILE *xtni, int xtni_words_max, char xtni_words[])
      Instead of having sw_xtni_eof, return a null pointer from get_xtni to denote end of file.
    • Check that fopen did not return a null pointer before accessing the file, and if the file was opened successfully, fclose it after you are done with it.
    • The xtni_words array has xtni_words_max elements. You should avoid accessing the array out of bounds by checking that xtni_num_words < xtni_words_max before using xtni_words[xtni_num_words].
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Dec 2015
    Location
    North-Central Indiana
    Posts
    17
    Thanks for the replies. The key was laserlight's last statement
    Quote Originally Posted by laserlight View Post
    The xtni_words array has xtni_words_max elements. You should avoid accessing the array out of bounds by checking that xtni_num_words < xtni_words_max before using xtni_words[xtni_num_words].
    Here is my solution...
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <stdbool.h>
    #include <ctype.h>
    
    /* Windows filenames */
    #define XTNI_FILENAME "In_Transactions.ofx" /* OFX */
    #define XTNI_LINE_LEN 55
    FILE *xtni;
    
    char *get_xtni(unsigned int xtni_words_max, int xtni_line_num, 
                       char xtni_words[])
    {
        static char xtni_line_cur[XTNI_LINE_LEN];
        if (fgets(xtni_line_cur, XTNI_LINE_LEN, xtni) == NULL) {
           return NULL;
        }
        // check for missing newline character (line length too small)
        if (xtni_line_cur[strlen(xtni_line_cur)-1] != '\n') {
           printf("Line length too small \n");
           printf("xtni_line_cur: %s\n", xtni_line_cur);
           getchar();
           return xtni_line_cur;
        }
    
        char * xtni_cur_word;
        int xtni_num_words = 0;
        xtni_cur_word = xtni_line_cur;
        printf("xtni_line_cur: %s\n", xtni_line_cur); // testing
        xtni_cur_word = strtok (xtni_cur_word," "); // first word
        while (xtni_cur_word != NULL) {
            strcpy(&xtni_words[xtni_num_words], xtni_cur_word);
            xtni_cur_word = strtok (NULL," "); // next word
            xtni_num_words++;
            }
    
        // check for max string length
        if (strlen(xtni_words) > xtni_words_max) {
           printf("xtni_words_max too low \n");
           printf("xtni_words_max: %i\n", xtni_words_max);
           printf("xtni_line_num: %i\n", xtni_line_num+1);
           getchar();
           return xtni_line_cur;
        }
    
        return xtni_line_cur;
    }
    
    int main()
    {
       xtni=fopen(XTNI_FILENAME, "r");
       if (xtni == NULL) {
           int errnum = errno;
           printf ("%d\n", errnum); // Convert int to char
           printf ("Error opening file. \n");
           printf ("Error Number: %i\n", errnum);
           printf ("File Name: %s\n", XTNI_FILENAME);
           printf ("Error message: %s\n", strerror(errnum));
       }
    
       unsigned int xtni_words_max = 48;
       char xtni_words[xtni_words_max];
       int xtni_line_num = 0;
       while (get_xtni(xtni_words_max, xtni_line_num, xtni_words) != NULL); {
          printf("%s", &xtni_words[0]);  // testing
          xtni_line_num++;
       }
    
       return 0;
    
    }
    Comments? Suggestions?

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,663
    > Comments? Suggestions?
    The while loop on line 66 isn't doing what you want.

    > printf("%s", &xtni_words[0]);
    Is a long way of saying printf("%s", xtni_words);

    > strcpy(&xtni_words[xtni_num_words], xtni_cur_word);
    You're not copying words into an array of words, you're copying into an array of chars.

    So if you have a line which reads "this is a test", your xtni_words array will contain on consecutive loops
    this
    tis
    tia
    tiatest
    Where each successive initial letter of each word on the line is preserved through xtni_num_words++;

    Even the most basic of testing on your part would have revealed that something was amiss.


    > if (strlen(xtni_words) > xtni_words_max)
    You need to check this before every attempt to modify xtni_words, not once at the end.
    If the condition is true at this point, it's already game over.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Dec 2015
    Location
    North-Central Indiana
    Posts
    17
    This is more educational than a class. Thanks.

    Quote Originally Posted by Salem View Post
    You need to check this before every attempt to modify xtni_words, not once at the end.
    If the condition is true at this point, it's already game over.
    Excellent observation. I modified it.

    Quote Originally Posted by Salem View Post
    > printf("%s", &xtni_words[0]);
    Is a long way of saying printf("%s", xtni_words);
    Thanks, I modified it.

    Quote Originally Posted by Salem View Post
    The while loop on line 66 isn't doing what you want.
    I copied in a couple of printf statements from my larger program as follows:

    Code:
        while (xtni_cur_word != NULL) {
            strcpy(&xtni_words[xtni_num_words], xtni_cur_word);
            xtni_cur_word = strtok (NULL," "); // next word
            printf("Word number: %i\n", xtni_num_words+1); //testing
            printf("Word: %s\n", &xtni_words[xtni_num_words]); //testing
            getchar(); // testing
            xtni_num_words++;
            }
    And here's an example of what I got:

    xtni_line_cur: <NAME>BORICS HAI
    R CARE ELKHART

    Word number: 1
    Word: <NAME>BORICS

    Word number: 2
    Word: HAIR

    Word number: 3
    Word: CARE

    Word number: 4
    Word: ELKHART
    This is exactly what I expect.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Segmentation fault? Strings
    By C_Nik in forum C Programming
    Replies: 4
    Last Post: 01-11-2013, 04:00 AM
  2. Segmentation fault (strings, pointers, Linux)
    By ankushwrites in forum C Programming
    Replies: 2
    Last Post: 03-25-2012, 12:00 PM
  3. Unable to join two strings due to Segmentation Fault
    By Orange Lozenge in forum C++ Programming
    Replies: 3
    Last Post: 09-15-2011, 04:00 PM
  4. Segmentation fault when appending to strings (char *)
    By LanguidLegend in forum C Programming
    Replies: 15
    Last Post: 02-24-2011, 07:35 PM
  5. Searching and matching strings: segmentation fault
    By Smola in forum C Programming
    Replies: 18
    Last Post: 07-11-2005, 12:25 AM