Home > Software engineering >  How to dynamically allocate string using void function?
How to dynamically allocate string using void function?

Time:01-08

First of all Thanks for visiting my question... :)

I am interested in competitive programming, so I daily do some amount of problem-solving, however, I only know C language at a decent level, and I often face problems while dynamically allocating something as usual, especially for strings and 2D arrays.

But I somehow manage to find ways (thanks to StackOverflow), for example, I wanted to create a function that scans string dynamically until the user enters space or new line, so I came up with the solution below and it works perfectly:

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

// scanf("%[^\n]%*c", str);
char *create_string(char *ptr)
{
    ptr = (char *)malloc(0 * sizeof(char));
    unsigned int size = 0;
    char c = 0;
    while (1)
    {
        scanf("%c", &c);
        if (c == 32 || c == 10)
        {
            break;
        }
        size  ;
        ptr = (char *)realloc(ptr, size * sizeof(char));
        ptr[size - 1] = c;
    }
    ptr = (char *)realloc(ptr, (size   1) * sizeof(char));
    ptr[size] = '\0';
    return ptr;
}

int main()
{
    char *str;
    str = create_string(str);
    printf("%s", str);
    printf("\n%lu", strlen(str));
    return 0;
}

And now for curiosity purposes, I want to know how can I do this same thing using the void function?, something like:

char *str;
create_string(&str);

should start storing everything in the dynamic memory which is pointed by str.

Also, please if you have more knowledge to show in DMA for 2D array, then please show me it, feel free to give examples with different problems.

And also How can I stop scanning the string (which was allocated dynamically) with specific string ending? for example, scanning(any kind of scanning, i.e. int, bool, custom structures etc...) should stop if user enters string "STOP", Please feel free to give pictorial examples.

Because I am sure that this question is burning like a fire in beginner's and intermediate C programmers' minds.

CodePudding user response:

As C passes arguments by value, to return something via an out parameter, you need to pass in a pointer to it. So to return a char * it would:

void create_string(char **s) {
  *s = malloc(42);
}

Here is your refactored code. I changed the following:

  1. Eliminate return value of update caller.
  2. Initialize *ptr = malloc(1) for the trailing '\0'. It eliminates an unnecessary and implementation defined malloc(0). This also eliminates the (*ptr)[size] = ... which looks wrong as the last index is expected to be size - 1. Alternatively initialize it to NULL.
  3. Use character constants instead of magic values (32, 10).
  4. sizeof(char) is defined as 1 so leave it out.
  5. Reduced scope of variable c.
  6. free() memory allocated.
  7. (cosmetic) Use size_t size instead of unsigned int size.
  8. (cosmetic) Avoid the noise of casting casting void *.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void create_string(char **ptr) {
    *ptr = malloc(1);
    size_t size = 1;
    for(;;) {
        char c;
        scanf("%c", &c);
        if (c == ' ' || c == '\n') break;
        (*ptr)[size - 1] = c;
        size  ;
        *ptr = realloc(*ptr, size);
    }
    (*ptr)[size-1] = '\0';
}

int main() {
    char *str;
    create_string(&str);
    printf("%s\n", str);
    printf("%zu\n", strlen(str));
    free(str);
}

I didn't fix these issue:

  1. Check return value of malloc(), realloc().
  2. v = realloc(v, ...) is unsafe and will leak memory if realloc() fails. You need to do char *tmp = realloc(v,...); if(!tmp) { // err }; v = tmp;.
  3. Check return value of scanf() otherwise you may be operating on uninitialized data.
  4. Use scanf("%s", ..) instead of for(;;) { scanf("%c", ...). It's more efficient to allocate a chunk at a time instead of per byte.
  5. If user enters ctrl-d (EOF) the program will go into an infinite loop.
  6. It's good idea to separate i/o from logic (i.e. let caller do the scanf(). That way create_string() is much more reusable.
  •  Tags:  
  • c
  • Related