Segmentation faulting in assignment

I'm currently learning C and I came from java. Our assignment asked us to count strings from either a file that could be added or it asks for the user to input a string. We just started using pointers and i looked up the different reasons why segmentation faults happened but I have no idea how to check for which issue it is. I initialized all my pointers to NULL but it still didn't work and from what i read that was the most common reason why a segmentation fault happens.

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

int debug = 0;

int
main(int argc, char **argv)
{
    extern char *optarg;
    extern int optind;
    FILE* infile = NULL;
    int c, err = 0; 
    int lflag = 0, sflag = 0, count = 0; //flags and count
    char *shortWord = NULL, *longWord = NULL; //variable for shortest and longest word
    int shortest = 100, longest = 0; //longest char 100, shortest 0
    char *string = NULL;
    char *pch = NULL;
    static char usage[] = "usage: %s [-l] [-s] [filename]n";

    while ((c = getopt(argc, argv, "ls")) != -1)
        switch (c) 
        {
            case 'l':
                lflag  = 1;
                break;
            case 's':
                sflag = 1;
                break; 
            case '?':
                err = 1;
                break;
        }

    if (err) 
    {
        fprintf(stderr, usage, argv[0]);
        exit(1);
    }
    //checks for file and then runs loop for word count
    infile = fopen("myfile.txt","r");
    if (infile != NULL)
    {
        fgets(string, 100, infile);
        pch = strtok (string, " ,.-");
        while(pch != NULL)
        {
            count++;
            if (strlen(pch) > longest)
                longWord = pch;
            if (strlen(pch) < shortest)
                shortWord = pch;
            pch = strtok (NULL, " ,.");
        }
    } 
    //else, asks for string
    else
    {
        printf("Enter your string: n");
        fgets(string, 100, stdin);
        int len = strlen(string);
        count = len;
        pch = strtok ( string, " ,.-");
        while(pch != NULL)
        {
            count++;
            if (strlen(pch) > longest)
                longWord = pch;
            if (strlen(pch) < shortest)
                shortWord = pch;
            pch = strtok (NULL, " ,.");
        }   
    }

    //following lines compute value based on arguments
    if(lflag == 1)
    {
        printf("Longest word is %s", longWord);
    }
    if(sflag ==  1)
    {
        printf("Shortest word is %s", shortWord);
    }

    printf("Word count = %.2dn", count);

    exit(0);
}

Their are some issues in your code:

  • You initialized string to NULL , then used it as an input buffer for fgets() . fgets() reqiures a pointer to an array of chars, either declared on the stack or dynamically allocated with malloc(3) . You can set an input buffer such as char string[100] .
  • fgets() must be checked, as it returns NULL when unable to read a line.
  • Your delimiter for strtok() is not accounting for the n character appended by fgets() . You can either remove this newline, or include it in the delimter. If you want to include it in the delimeter, make sure your delimiter is " ,.-n" .
  • You could create function which parses your input with strtok() , as this would allow your main() to be shorter and reduce the repetitiveness in the code. An example function prototype could be void longest_shortest_words(char line[], char **longest, char **shortest, size_t *word_count); , whereby you pass the longest, shortest words along with the number of words back to main() via pointers. You could also just store the longest and shortest words in a 2D array or array of pointers.
  • You should also explicitly check that your file was opened correctly. Something like this should be included:

     infile = fopen("myfile.txt", "r");
     if (infile == NULL) {
         fprintf(stderr, "Failed to open filen");
         exit(EXIT_FAILURE);
     }
    
  • When checking opt , checking ? as a character in your switch statement is not right. Instead of:

    case '?':
        err = 1;
        break;
    

    Use default , which covers any other invalid option entered. Here is how you can use it:

    default:
        fprintf(stderr, "usage: %s [-l] [-s] [filename]n", argv[0]);
        exit(EXIT_FAILURE);
    
  • Checking sflag and lflag at the end is not enough. You should check if longWord and shortWord are not NULL .

  • Here is some example code which demonstrates these points:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #define LINESIZE 100
    
    void longest_shortest_words(char line[], char **longest, char **shortest, size_t *wordcount);
    void print_output(int lflag, int sflag, char *longword, char *shortword, size_t wordcount);
    void remove_newline(char line[]);
    
    int main(int argc, char * const argv[]) {
        FILE *infile;
        char line[LINESIZE] = {''};
        int opt, sflag = 0, lflag = 0;
        size_t wordcount = 0;
        const char *optstr = "ls";
        char *longword = NULL, *shortword = NULL;
    
        while ((opt = getopt(argc, argv, optstr)) != -1) {
            switch(opt) {
                case 'l':
                    lflag = 1;
                    break;
                case 's':
                    sflag = 1;
                    break;
                default:
                    fprintf(stderr, "usage: %s [-l] [-s] [filename]n", argv[0]); 
                    exit(EXIT_FAILURE);
            }
        }
    
        /* Checking if file is in directory */
        infile = fopen("myfile.txt", "r");
        if (infile == NULL) {
            fprintf(stderr, "Failed to open filen");
            exit(EXIT_FAILURE);
        }
    
        /* checking if line exists in file */
        if (fgets(line, LINESIZE, infile) == NULL) {
            fprintf(stderr, "No line found in file.n");
    
            printf("nEnter string instead:n");
            if (fgets(line, LINESIZE, stdin) != NULL) {
                remove_newline(line);
                longest_shortest_words(line, &longword, &shortword, &wordcount);   
                /* checking that longWord, shortWord and word_count are valid */
                if (longword != NULL && shortword != NULL && wordcount > 0) {
                    print_output(lflag, sflag, longword, shortword, wordcount);
                }
            }
    
        /* file has line, do stuff with it */
        } else {
            remove_newline(line);
            longest_shortest_words(line, &longword, &shortword, &wordcount);
            print_output(lflag, sflag, longword, shortword, wordcount);
        }
    
        exit(EXIT_SUCCESS);
    }
    
    /* function for printing output, can be improved */
    void print_output(int lflag, int sflag, char *longword, char *shortword, size_t wordcount) {
        if (lflag) {
            printf("Longest word: %sn", longword);
        }
    
        if (sflag) {
            printf("Shortest word: %sn", shortword);
        }
    
        if (wordcount > 0) {
            printf("Word count = %zun", wordcount);
        }
    }
    
    /* function for removing newline, and checking that input hasnt exceeded limit */
    void remove_newline(char line[]) {
        size_t slen;
    
        slen = strlen(line);
        if (slen > 0 && line[slen-1] == 'n') {
            line[slen-1] = '';
        } else {
            fprintf(stderr, "nToo many characters in input.n");
            exit(EXIT_FAILURE);
        }
    }
    
    /* function which parses line, and saves longWord and shortWord in pointers */
    void longest_shortest_words(char line[], char **longword, char **shortword, size_t *wordcount) {
        char *word = NULL;
        const char *delim = " ,.";
    
        word = strtok(line, delim);
        if (word != NULL) {
            *longword = word;
            *shortword = word;
            *wordcount = 1;
        }
    
        while ((word = strtok(NULL, delim)) != NULL) {
            (*wordcount)++;
            if (strlen(word) > strlen(*longword)) {
                *longword = word;
            } else if (strlen(word) < strlen(*shortword)) {
                *shortword = word;
            } 
        }
    }
    

    Note: The code shown above can be improved, it is just to show you another approach to your problem.

    链接地址: http://www.djcxy.com/p/43900.html

    上一篇: malloc()和free()如何工作?

    下一篇: 分配错误分配