Hello, OnlineGDB Q&A section lets you put your programming query to fellow community users. Asking a solution for whole assignment is strictly not allowed. You may ask for help where you are stuck. Try to add as much information as possible so that fellow users can know about your problem statement easily.

Segmentation fault in C code

+2 votes
asked Nov 13, 2020 by Sweidan Omar (150 points)
Hello, All!

When I try to run this code in debug mode, I get a segmentation fault:

#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* readline();
char** split_string(char*);

// Complete the minimumBribes function below.
void minimumBribes(int q_count, int* q) {
    int numberOfBribes= 0;
    int i= 0;
    
    for (; i < q_count; i++) {
        if(q[i] != (i+1)){
            numberOfBribes+= abs(q[i] - (i+1));
        }
    }
    
    if(i < q_count){
        printf("Too chaotic\n");
    }
    else{
        printf("%d\n", numberOfBribes);
    }
}

int main()
{
    char* t_endptr;
    char* t_str = readline();
    int t = strtol(t_str, &t_endptr, 10);

    if (t_endptr == t_str || *t_endptr != '\0') { exit(EXIT_FAILURE); }

    for (int t_itr = 0; t_itr < t; t_itr++) {
        char* n_endptr;
        char* n_str = readline();
        int n = strtol(n_str, &n_endptr, 10);

        if (n_endptr == n_str || *n_endptr != '\0') { exit(EXIT_FAILURE); }

        char** q_temp = split_string(readline());

        int* q = malloc(n * sizeof(int));

        for (int i = 0; i < n; i++) {
            char* q_item_endptr;
            char* q_item_str = *(q_temp + i);
            int q_item = strtol(q_item_str, &q_item_endptr, 10);

            if (q_item_endptr == q_item_str || *q_item_endptr != '\0') { exit(EXIT_FAILURE); }

            *(q + i) = q_item;
        }

        int q_count = n;

        minimumBribes(q_count, q);
    }

    return 0;
}

char* readline() {
    size_t alloc_length = 1024;
    size_t data_length = 0;
    char* data = malloc(alloc_length);

    while (true) {
        char* cursor = data + data_length;
        char* line = fgets(cursor, alloc_length - data_length, stdin);

        if (!line) { break; }

        data_length += strlen(cursor);

        if (data_length < alloc_length - 1 || data[data_length - 1] == '\n') { break; }

        size_t new_length = alloc_length << 1;
        data = realloc(data, new_length);

        if (!data) { break; }

        alloc_length = new_length;
    }

    if (data[data_length - 1] == '\n') {
        data[data_length - 1] = '\0';
    }

    data = realloc(data, data_length);

    return data;
}

char** split_string(char* str) {
    char** splits = NULL;
    char* token = strtok(str, " ");

    int spaces = 0;

    while (token) {
        splits = realloc(splits, sizeof(char*) * ++spaces);
        if (!splits) {
            return splits;
        }

        splits[spaces - 1] = token;

        token = strtok(NULL, " ");
    }

    return splits;
}

Any comments/suggestions are welcomed.

1 Answer

+1 vote
answered Nov 16, 2020 by Peter Minarik (86,040 points)

Give instructions to the user, what to do

When you write your code, you may remember when and what input is required. But maybe a few days/weeks later it wouldn't be so clear. For a 3rd party (e.g. people try to look at your code) it could be quite difficult to understand what you're trying to achieve if you have no instructions printed on the screen or no comment in your code.

Source of the segmentation fault

I've looked into your code (added some printing to the screen to allow better tracking what the program does and what the user is required to do). I still do not have a proper understanding of what you're trying to do, but the problem is within the 
for (int i = 0; i < n; i++)
loop.
The problem is, that you repeat this loop n times (which was a user input) on q_temp, which is another user input. To be exact, on the split segments of q_temp. Now, the problem is, that this would work only properly, when n matches the number of segments in q_temp. That's probably hardly ever the case.
I'd suggest rethinking of your code.
Probably the best option is to repeat the loop as long as q_temp has unprocessed segments and not based on a fixed number (n).
Welcome to OnlineGDB Q&A, where you can ask questions related to programming and OnlineGDB IDE and and receive answers from other members of the community.
...