Reputation: 23
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.
Upvotes: 1
Views: 71
Reputation:
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:
*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
.sizeof(char)
is defined as 1 so leave it out.c
.free()
memory allocated.size_t size
instead of unsigned int size
.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:
malloc()
, realloc()
.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;
.scanf()
otherwise you may be operating on uninitialized data.scanf("%s", ..)
instead of for(;;) { scanf("%c", ...)
. It's more efficient to allocate a chunk at a time instead of per byte.ctrl-d
(EOF) the program will go into an infinite loop.scanf()
. That way create_string()
is much more reusable.Upvotes: 4