String isn't getting mutated after using a function, despite being mutated inside the function c language

37 views Asked by At

Quick summary - I am testing my functions, and for that, I've decided to write my own add_as_first() and add_as_last() functions, which are adding character to the old string array, through creating a new one and making a copy, without using default c language string functions. And for some reason, one out of two string arrays isn't behaving like I would like it to do. I've added strlen() function for debugging and I can see that inside a print_file function my string array is perfectly healthy and growing bigger as the function goes through its cycles. But for some reason, when the function ends, one of the string "res" is back to 0 length, while, the second string, "body", got properly mutated and has a value which is supposed to have. The difference between them is that "res" is getting filled by using add_as_last() function inside a print_file loop function, while, "body" is getting filled by using add_as_first() function inside a forming_list() function, which is inside print_file(). Any idea why it behaves this way? It looks like scoping issues but it should work properly, considering that both "body" and "res" are being used in about the same way.

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

#define x_size 4
#define y_size 4


char* add_as_first(char *given_arr, char given_char, int check) {
    int strLen = 0;
    while (given_arr[strLen] != '\0') {
        strLen++;
    }
    char *new_arr;
    new_arr = (char*)malloc((strLen + 1 + 1) * sizeof(char));
    
    new_arr[0] = given_char;
    int i = 0;

    for (; i < strLen; i++) {
        new_arr[i + 1] = given_arr[i]; 
    }
    new_arr[i + 1] = '\0';
    if ((i + 1 + 1) != (strLen + 1 + 1)) {
        printf("WE GOT A MEMORY LEAK OUT THERE\n");
    }

    if (check != 0) {
        free(given_arr);
    }
    return new_arr;
}

char* add_as_last(char *given_arr, char given_char, int check) {
    int strLen = 0; 
    while (given_arr[strLen] != '\0') {
        strLen++;
    }
    char* newString = (char*)malloc((strLen + 1 + 1) * sizeof(char));
    int i = 0;

    for(; i < strLen; i++) {
        newString[i] = given_arr[i];
            
    }

    newString[i] = given_char;
    newString[i + 1] = '\0';
    if ((i + 1 + 1) != (strLen + 1 + 1)) {
        printf("WE GOT A MEMORY LEAK OUT THERE\n");
    }
    return newString;
}

void forming_list(int file_arr[][y_size], int i, int j, char body[]) {
    char thing = '0';
    thing = j + '0';
    body = add_as_first(body, thing, 1);
    body = add_as_first(body, ',', 1);
    thing = i + '0';
    body = add_as_first(body, thing, 1);
    body = add_as_first(body, ' ', 1);
    if ((file_arr[i][j] == 1) || (file_arr[i][j] == 5)) {
        if (j < x_size - 1) {
            forming_list(file_arr, i, j + 1, body);
        } else {
            forming_list(file_arr, i + 1, 0, body);
        }
    } else if ((file_arr[i][j] == 2) || (file_arr[i][j] == 6)) {
        if (j != 0) {
            forming_list(file_arr, i, j - 1, body);
        } else {
            forming_list(file_arr, i - 1, x_size - 1, body);
        } 
    } else if ((file_arr[i][j] == 3) || (file_arr[i][j] == 7)) {
        if (i == 0) {
            forming_list(file_arr, y_size - 1, j, body);
        } else {
            forming_list(file_arr, i - 1, j, body);
        } 
    } else if ((file_arr[i][j] == 4) || (file_arr[i][j] == 8)) {
        if (i == y_size - 1) {
            forming_list(file_arr, 0, j, body);
        } else {
            forming_list(file_arr, i + 1, j, body);
        } 
    } 
}

void print_file(int file_arr[][y_size], char *res, char *body) {
    int i = 0;
    int j = 0;
    for(i; i < y_size; i++) {
        for (j; j < x_size; j++) {
            if ((file_arr[i][j] >= 5) && (file_arr[i][j] <= 9)) {
                res = add_as_last(res, '#', 1);
            } 
            else if ((file_arr[i][j] >= 1) && (file_arr[i][j] <= 4)) {
                res = add_as_last(res, '#', 1);
                forming_list(file_arr, i, j, body); 
            } else {
                res = add_as_last(res, 'x', 1);
            }
        }
        res = add_as_last(res, '\n', 1);
        printf("Length of string = %zu \n",strlen(res));
        j = 0;
    }
}

int main()
{

    int disp[x_size][y_size] = {
    {0, 1, 8, 0},
    {0, 0, 8, 0},
    {0, 9, 6, 0},
    {0, 0, 0, 0}
};
    char *res;
    char *body;
    res = (char*)malloc((1) * sizeof(char));
    body = (char*)malloc((1) * sizeof(char));

    res[0] = '\0';
    body[0] = '\0';
    printf("Length of string = %zu \n",strlen(res));
    print_file(disp, res, body);
    printf("Length of string = %zu \n",strlen(res));
    printf("%s\n", res);
    printf("%s\n", body);
    return 0;
}

The output is:

Length of string = 0 //After creating a res line

Length of string = 5 //After the first outer for loop

Length of string = 10 //After the second outer for loop

Length of string = 15 //After the third outer for loop

Length of string = 20 //After the fourth outer for loop just before exiting function

Length of string = 0 //Outside the function before printing "res" string

                  //Printing empty "res" string

2,1 2,2 1,2 0,2 0,1 //Printing properly filled "body" string

Why "body" and "res" value is so different after my program is finished working, despite being so similar?

1

There are 1 answers

12
Aganju On

Your print_file function is modifying res, but the new pointer never gets passed back into main.
So main has its res still pointing to the (long destroyed) original res, which produces undefined bahavior for strlen (or anything else).

You should pass the res pointer by reference or pass the pointer to it, so the modification gets back into main.