Search code examples
cstringrealloc

How to shrink string by using Realloc


First time asking a question here: well I need to take the original string and remove the spaces and numbers from the string I need to use the exact amount of memory.

For some reason, the string is fine in the beginning but then it prints garbage values:

original string: "abcd2 34fty 78 jurt#"
what needed to be done: abcdftyjurt#

My code:

#define _CRT_SECURE_NO_WARNINGS

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

/* Function declarations */

/*-------------------------------------------------------------*/
void Ex1();
char* clearDigitsAndSpaces(char*);
/*-------------------------------------------------------------*/
void Ex2();

/*-------------------------------------------------------------*/
void Ex3();

/*-------------------------------------------------------------*/
/* Declarations of other functions */

int main() {
    int select = 0, i, all_Ex_in_loop = 0;
    printf("Run menu once or cyclically?\n(Once - enter 0, cyclically - enter other number) ");
    if (scanf("%d", &all_Ex_in_loop) == 1)
        do {
            for (i = 1; i <= 3; i++)
                printf("Ex%d--->%d\n", i, i);
            printf("EXIT-->0\n");
            do {
                select = 0;
                printf("please select 0-3 : ");
                scanf("%d", &select);
            } while ((select < 0) || (select > 3));
            switch (select) {
            case 1: Ex1(); break;
            case 2: Ex2(); break;
            case 3: Ex3(); break;
            }
        } while (all_Ex_in_loop && select);
        return 0;
}

/* Function definitions */

void Ex1() {
    char input[] = "abcd2 34fty    78 jurt#";
    char *temp = NULL;
    temp = clearDigitsAndSpaces(input);
    printf("%s\n ", temp);
    free(temp);
}

char *clearDigitsAndSpaces(char *old_string) {
    char *new_string;
    int count = 0;
    int i = 0;
    int j = 0;
    int size = strlen(old_string);
    new_string = (char *)malloc(size * sizeof(char));
    assert(new_string); /*Memory allocation check*/
    while (old_string[i]) {
        if (old_string[i] != ' ' && (old_string[i] > '9' || old_string[i] < '0')) {
            new_string[j++] = old_string[i];
        } else {
            //size -= 1;
            new_string = (char *)realloc(new_string, size - 1);
        }
        i++;
    }
    assert(new_string);
    //printf("%s", new_string);
    return new_string;
}

void Ex2() {
}

void Ex3() {
}

Solution

  • The problem in your code is you must allocate one extra byte for the null terminator.

    You can avoid using realloc() by first scanning the source string to determine the allocation size and then use a separate loop to copy the contents:

    char *clearDigitsAndSpaces(const char *src) {
        char *new_string;
        size_t size = 1; // 1 extra byte for the null terminator.
    
        for (size_t i = 0; src[i] != '\0'; i++) {
            if (src[i] != ' ' && !(src[i] >= '0' && src[i] <= '9'))
                size++;
        }
        new_string = malloc(size);
        if (new_string) {
            size_t j = 0;
            for (size_t i = 0; src[i] != '\0'; i++) {
                if (src[i] != ' ' && !(src[i] >= '0' && src[i] <= '9'))
                    new_string[j++] = src[i];
            }
            new_string[j] = '\0';  // set the null terminator
        }
        return new_string;
    }