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:
- Eliminate return value of update caller.
- Initialize
*ptr = malloc(1)
for the trailing '\0'. It eliminates an unnecessary and implementation definedmalloc(0)
. This also eliminates the(*ptr)[size] = ...
which looks wrong as the last index is expected to besize - 1
. Alternatively initialize it toNULL
. - Use character constants instead of magic values (32, 10).
sizeof(char)
is defined as 1 so leave it out.- Reduced scope of variable
c
. free()
memory allocated.- (cosmetic) Use
size_t size
instead ofunsigned int size
. - (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:
- Check return value of
malloc()
,realloc()
. v = realloc(v, ...)
is unsafe and will leak memory ifrealloc()
fails. You need to dochar *tmp = realloc(v,...); if(!tmp) { // err }; v = tmp;
.- Check return value of
scanf()
otherwise you may be operating on uninitialized data. - Use
scanf("%s", ..)
instead offor(;;) { scanf("%c", ...)
. It's more efficient to allocate a chunk at a time instead of per byte. - If user enters
ctrl-d
(EOF) the program will go into an infinite loop. - It's good idea to separate i/o from logic (i.e. let caller do the
scanf()
. That waycreate_string()
is much more reusable.