0

I'm developing a function in C that sorts text around a given key. Let's say you have the following file:

this line is first
but this line is second
finally there is this line

If you run the program and give it this file as input, it should print:

but this line is second
finally there is this line
this line is first

because but is alphabetically before finally is before this .

If, however, you pass in a flag to sort a different key, you'll get a different output. For example, if you call fastsort -2 on this file, you should get:

this line is first
finally there is this line
but this line is second

because line comes before there comes before this . Yes, I am assuming -2 means the second word in each line (like most people would, except computer scientists who always want to start at 0).

Moreover, if the specified key does not exist on a particular line of the input file, I should just use the last word of that line as the key. For example, if the user wants to sort on the 4th word ( -4 ), and the sort encounters a line like this ( sample line ), the sort should use the word line to sort that line.

My problem comes from this last assumption, I'm using strtok() to extract the word given by the key but I get a segmentation fault if the key is bigger than the number of words in the line. Here is the body of the function;

 typedef struct {
     char word[128];
     int index;
 } wordIndex;

char** fastsort(char** text, int word){

char** sortedText;
char* LineAux;
int i;
wordIndex tokenLines[numLines];

for(i=0; i<numLines; i++){
    char* token;
    int j = 0; //counter

    LineAux = (char*) malloc(MAX_LENGTH*sizeof(char)); //MAX_LENGTH = 128
    if (LineAux==NULL){
        fprintf(stderr,"Error, malloc failed");
        exit(1);
    }

    strcpy(LineAux,text[i]);

    token = strtok(LineAux, " \n");
    j++;

    if(token == NULL){ //if blank line
        token=" ";

    } else {

        while(token != NULL){  //segmentation fault
            if(j == word){
                break;
            }
            token = strtok(NULL, " \n");
            j++;

        }
    }

    strcpy(tokenLines[i].word,token);
    tokenLines[i].index=i;
    free(LineAux); //free Aux string
    printf("token: %s   Line: %d  \n",tokenLines[i].word, tokenLines[i].index);
}

qsort(tokenLines,numLines,sizeof(wordIndex),compareTo); //sorting tokens

sortedText = (char**) malloc(numLines*sizeof(char*));
if (sortedText==NULL){
    fprintf(stderr,"Error, malloc failed");
    exit(1);
}


//reordering text
int n; 
for (n=0; n<numLines; n++){
    int index;

    sortedText[n]=(char*) malloc(MAX_LENGHT*sizeof(char));

    if (sortedText[n]==NULL){
        fprintf(stderr,"Error, malloc failed");
        exit(1);
    }

    index = tokenLines[n].index;
    strcpy(sortedText[n],text[index]);

}


return sortedText;

}

the segmentation fault appears inside the while loop. Hope you can help, Thank you in advance.

4
  • Can text[i] ever be longer than 127 characters plus the terminating byte? Because if it can, your strcpy is going to overrun LineAux's bounds. Same goes for text[index] further down. Commented Oct 8, 2017 at 18:55
  • @CharlesSrstka No, I have another function (which extracts the text from the file) that prevents the line from having more than 127 characters (+ terminating) so it will never be longer than that Commented Oct 8, 2017 at 19:01
  • What's wordIndex? Some sort of struct I take it? Commented Oct 8, 2017 at 19:02
  • I wrote an answer which I think explains your crash. Commented Oct 8, 2017 at 19:26

2 Answers 2

1

I ran the code above on my machine. It works, with one caveat; word is 1-indexed instead of 0 like you might expect, since j is incremented before ever comparing it to anything. So if you enter 0, as you naturally would if you wanted to sort by the first word, this line is never going to be true:

if(j == word){

Therefore, your while loop continues until token is NULL. Then, after the loop, your strcpy crashes, because it tried to deference the null pointer you passed to it:

strcpy(tokenLines[i].word,token); // don't NULL me bro!

This is the source of your crash. To fix it, I'd make two changes:

  1. Get rid of the j++ before the loop. Let the indexing start at 0, since that is what is usually done in C and what a user of the function would normally expect.

  2. After the loop is over, test token to see if it is NULL. If it is, gracefully exit the function, maybe returning some kind of error to the user. Crashing if someone enters an invalid word number is bad UI.

Sign up to request clarification or add additional context in comments.

Comments

0

Allrigth , I have the solution;

The problem was the order of the instructions inside the while loop.

Here is the working solution:

/**
 * Function that sorts text by a given key
 * @param text: array of strings which is going to be sorted
 * @param word: key where the sort starts
 * @return sorted text
 */
char** fastsort(char** text, int word){

    char** sortedText;
    char* LineAux;
    int i;
    wordIndex tokenLines[numLines];

    for(i=0; i<numLines; i++){
        char* token;
        int j = 0; //counter

        LineAux = (char*) malloc(MAX_LENGHT*sizeof(char));
        if (LineAux==NULL){
            fprintf(stderr,"Error, malloc failed");
            exit(1);
        }

        strcpy(LineAux,text[i]);

        token = strtok(LineAux, " \n");
        j++;

        if(token == NULL){ //if blank line
            token=" ";

        } else {

            while(token != NULL){  //segmentation fault
                strcpy(tokenLines[i].word,token);
                if(j == word){
                    break;
                }

                token = strtok(NULL, " \n");
                j++;

            }
        }

        tokenLines[i].index=i;
        free(LineAux); //free Aux string
    }

As you can see, the change is not very efficient but It does work for now, if you have an alternate solution I'll be glad to try it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.