Expanding array dynamicly after user enter string in function dynamic_array My Problem seems to be when i try to use the extended array agian in main after i dynamic_array returns true.
After function call i try to print input with printf("main string: %s\n", input) the program will crash. It seems like the *input in main never gets extended.
int dynamic_array(char *input, int *string_current_len){
int string_len = 0;
char temp_c;
input = (char *) malloc(sizeof(char));
if(input == NULL) {
printf("Could not allocate memory!");
exit(1);
}
printf("File to search in: ");
while((temp_c = getchar()) != '\n') {
realloc(input, (sizeof(char)));
input[string_len++] = temp_c;
}
input[string_len] = '\0';
printf("\nYou entered the string: %s\n", input);
printf("length of string is %d.\n", string_len);
*string_current_len = string_len;
return 1;
}
int main(void) {
int string_len = 0;
char *input;
printf("enter #q as filename or word to quit.\n");
if(!dynamic_array(input, &string_len)){
return 0;
}
printf("main string: %s\n", input);
return 0;
}
This:
realloc(input, (sizeof(char)));
is wrong. The realloc() function doesn't modify the given pointer (it can't!), it returns the new pointer. It can also fail, and return NULL.
Also, the second argument doesn't make any sense at all, it should be the new desired total size of the previously allocated buffer, but you're always passing (a very obscure) 1. It's not "grow this by this amount", it's the rather more low-level "attempt to grow this to this new size, and return the new location of the grown buffer".
Please read the documentation very carefully.
realloc(input, (sizeof(char)));
You are reallocating with same size (i.e 1 byte). It shoud be:
while((temp_c = getchar()) != '\n') {
realloc(input, (string_len + 1) * (sizeof(char)));
input[string_len++] = temp_c;
if(!dynamic_array(input, &string_len)){
return 0;
}
"input" variable is used without initialization.
realloc(input, (sizeof(char)));
Above "realloc" is returning bad pointer. It may be totally bogus, or it may have been allocated from another heap. The pointer MUST come from the 'local' heap.
C has a call-by-value semantics. So any changes to formal input inside dynamic_array is not propagated to the caller (e.g. your main).
Your main does not initialize input. If you compiled with all warnings and debug info (as you should), e.g. with gcc -Wall -g, you'll get a warning about that.
I actually recommend to initialize every local variable. This makes the debugging easier (since runs are more reproductible). Useless initializations will be removed by the optimizer.
You could initialize input inside your main with
char* input = NULL;
and you should redesign your program, perhaps by having a grow_array function (instead of your dynamic_array) which you would call in your main like
grow_array (&input, &string_len);
I leave up to you to declare and implement grow_array correctly. I'm too lame to do your homework.
Inside your grow_array you want to call malloc and test it:
*pptr = malloc(newsize);
if (!*pptr) { perror ("malloc"); exit (EXIT_FAILURE); };
Don't forget to use the debugger (gdb) to run your program step by step.
I don't recommend using realloc because error handling could be tricky. I would suggest using malloc and free and cleverly copying the data using mempcy.
Read the documentation of every function that you are using, e.g. malloc(3), printf(3)
couple of things that I noticed.
int dynamic_array(char *input, int *string_current_len) should change to
int dynamic_array(char **input, int *string_current_len)
since this function is trying to modify a pointer.
also the call to the function here
if(!dynamic_array(input, &string_len)){
return 0;
}
needs to be:
if(!dynamic_array(&input, &string_len)){
return 0;
}
Related
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.
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 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.
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 of unsigned 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 if realloc() fails. You need to do char *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 of for(;;) { 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 way create_string() is much more reusable.
I think I've got everything fixed now. I made the mistake of incrementing the environ variable instead of treating it like an array and iterating across it. The following is what I have now and it should be good to go.
extern char **environ;
int main(int argc, char *argv[]) {
// determine number of environment variables
int n = 0;
char *c = NULL;
while ((c = environ[n++]) != NULL) {
printf("%s\n", c);
}
printf("%s\n%d\n\n", c, n);
// allocate array to store character pointers to environment array
char **new_c;
printf("This prints\n");
if ((new_c = malloc(n * sizeof(*c))) == NULL) {
printf("Error\n");
exit(EXIT_FAILURE);
}
printf("This prints now too\n");
free(c);
// sort array of character pointers
// parse each environment variable and output
exit(0);
}
To start, I've read through a couple dozen malloc & segmentation fault questions on here and none seem to be the same as mine. That being said, if this is a duplicate question would you mine pointing me to the solution?
Hi all, I'm having a problem using malloc. I compiled and ran my program once and malloc worked. I then began filling in more code to solve the problem and since that first run I have received a Segmentation Fault. Below is my code in it's last working state (still giving a seg fault error though):
extern char **environ;
int main(int argc, char *argv[]) {
// determine number of environment variables
int n = 0;
char *c = *environ;
while ((c = *environ++) != NULL) {
n++;
printf("%s\n", c);
}
printf("%s\n%d\n\n", c, n);
// allocate array to store character pointers to environment array
printf("This prints\n");
if ((c = malloc((size_t) n)) == NULL) {
perror("Unable to allocate memory\n");
}
printf("This does not print\n");
free(c);
// sort array of character pointers
// parse each environment variable and output
exit(0);
}
The program is supposed to allocate memory for a char array that will then be used to sort, parse, and print the name-value or value-name pairs depending on what the FORMAT value is set to. The first loop works and iterates through the environ variable and prints out each name-value pair. The two printf statements I included state what I see in the terminal. Does anyone have any ideas what I'm doing wrong?
Also, I have tried using the following malloc lines:
char *new_c = malloc((size_t) n);
char *new_c = malloc(n);
char *new_c = malloc(1);
char *new_c = malloc(sizeof(n));
int *ptr = malloc((size_t) n);
There are probably a few others I tried but I'm still baffled. There are so few lines of code that I'm not sure how I could be messing anything up this early on. Also, for giggles here's what I get when I use free in the terminal (showing I have memory available):
total used free shared buff/cache available
Mem: 3036836 1404340 902852 104712 729644 1491248
Swap: 0 0 0
I've also tried calling malloc outside of the if statement as such:
c = malloc((size_t) n);
if (c == NULL) {
perror("Unable to allocate memory\n");
}
Here you are modifying the global environ:
while ((c = *environ++) != NULL) {
After the while loop, environ points to uninitialized memory.
malloc() looks for some environment variables which can modify its behaviour and is now dereferencing a pointer to uninitialized memory.
Use this:
int i = 0;
while ((c = environ[i++]) != NULL) {
This should fix the segmentation fault.
Two things with this:
if ((c = malloc((size_t) n)) == NULL) {
perror("Unable to allocate memory\n");
}
You are allocating n bytes, here. It sounds like you want to allocate space for n pointers to char, so you should replace with:
malloc(n * sizeof(char *))
If this is indeed what you're trying to do, then c should be char **, not char *, and better still would be:
c = malloc(n * sizeof *c)
Incidentally, you appear to be using c for two completely different things. It's generally better not to do this with variables - since it makes your program harder to understand - and instead to use one variable to loop through to print your environment variables, and a different one to store your dynamically allocated array.
Also, you call perror() if malloc() fails, but then you just continue right on with your program as if there was no error. You should actually respond to a failure of this nature, if nothing else by calling exit(EXIT_FAILURE) after reporting it.
I am trying to create a C function I can call in small programs I write, to accept user input:
char GetStringMine()
{
int i = 0;
char ch;
char * tmpstring = (char *) malloc(2048 * sizeof(char));
while(ch != '\n')
{
ch = getchar();
tmpstring[i++] = ch;
}
tmpstring[i] = '\0';
return * tmpstring;
free(tmpstring);
}
But it does not compile.
Please can you tell me what I am doing wrong, and what I can do better?
First thing:
In your code,
while(ch != '\n')
invokes undefined behavior, as ch is an automatic local variable and unless initialized explicitly, it contains an indeterminate value. Trying to read an indeterminate value is UB.
Second thing,
free(tmpstring);
after the return statement has no effect, at all. Just remove it.
Third thing:
Please see this discussion on why not to cast the return value of malloc() and family in C..
Fourth thing:
As per your return statement, the function return type should be of char *, instead of a char.
Finally
But it does not compile
cannot be answered in current form. You need to provide more information in your question to clarify "what" and "how".
You are trying to return a char pointer(char*) but the return type is a char. Also you should consider other comments too.
char* GetStringMine()
{
int i = 0;
char ch;
char * tmpstring = (char *) malloc(2048 * sizeof(char));
while(ch != '\n')
{
ch = getchar();
tmpstring[i++] = ch;
}
tmpstring[i] = '\0';
return tmpstring;
}
The worst thing about this code is that you're trying return a pointer to a local variable. The variable tmpstring is destroyed after the execution of your function is complete (i.e. on your return statement).
To correct this, you should ask a char* as a parameter, and store the read characters in it (careful with the overflows if you're going with this solution).
Or, you could declare tmpstring as a static char tmpstring[2048] = {0};. static means it won't be destroyed after the function is over. Although I've seen that kind of things in the standard library sometimes, I wouldn't recommend it since the contents will be erased when the function is called again.
For the other problems, see the previous answers.
Try this...
static char tmpstring[2048] = {0};
char* GetStringMine()
{
int i = 0;
char ch = 0;
while(ch != '\n')
{
ch = getchar();
tmpstring[i++] = ch;
}
return tmpstring;
}
You cannot free the allocated memory then return a pointer to it, the data will be gone
No need to use malloc, as you are not dynamically allocating the array(1)
Return a char*, not a char
(1) In your example you effectively are fixing the size of memory to 2048. Think about protecting against a buffer overrun - what will happen if a user enters more than 2048 characters, and how will you protect your code against this.
In a real world application you would need to reallocate if going over the allotted size, or restrict the amount of input for the memory allocated.
I created a function designed to get user input. It requires that memory be allocated to the variable holding the user input; however, that variable is returned at the end of the function. What is the proper method to free the allocated memory/return the value of the variable?
Here is the code:
char *input = malloc(MAX_SIZE*sizeof(char*));
int i = 0;
char c;
while((c = getchar()) != '\n' && c != EOF) {
input[i++] = c;
}
return input;
Should I return the address of input and free it after it is used?
Curious as to the most proper method to free the input variable.
It's quite simple, as long as you pass to free() the same pointer returned by malloc() it's fine.
For example
char *readInput(size_t size)
{
char *input;
int chr;
input = malloc(size + 1);
if (input == NULL)
return NULL;
while ((i < size) && ((chr = getchar()) != '\n') && (chr != EOF))
input[i++] = chr;
input[size] = '\0'; /* nul terminate the array, so it can be a string */
return input;
}
int main(void)
{
char *input;
input = readInput(100);
if (input == NULL)
return -1;
printf("input: %s\n", input);
/* now you can free it */
free(input);
return 0;
}
What you should never do is something like
free(input + n);
because input + n is not the pointer return by malloc().
But your code, has other issues you should take care of
You are allocating space for MAX_SIZE chars so you should multiply by sizeof(char) which is 1, instead of sizeof(char *) which would allocate MAX_SIZE pointers, and also you could make MAX_SIZE a function parameter instead, because if you are allocating a fixed buffer, you could define an array in main() with size MAX_SIZE like char input[MAX_SIZE], and pass it to readInput() as a parameter, thus avoiding malloc() and free().
You are allocating that much space but you don't prevent overflow in your while loop, you should verify that i < MAX_SIZE.
You could write a function with return type char*, return input, and ask the user to call free once their done with the data.
You could also ask the user to pass in a properly sized buffer themselves, together with a buffer size limit, and return how many characters were written to the buffer.
This is a classic c case. A function mallocs memory for its result, the caller must free the returned value. You are now walking onto the thin ice of c memory leaks. 2 reasons
First ; there is no way for you to communicate the free requirement in an enforceable way (ie the compiler or runtime can't help you - contrast with specifying what the argument types are ). You just have to document it somewhere and hope that the caller has read your docs
Second: even if the caller knows to free the result he might make a mistake, some error path gets taken that doesnt free the memory. This doesnt cause an immediate error, things seem to work, but after running for 3 weeks your app crashes after running out of memory
This is why so many 'modern' languages focus on this topic, c++ smart pointers, Java, C#, etc garbage collection,...
I need a function/method that will take in a char array and set it to a string read from stdin. It needs to return the last character read as its return type, so I can determine if it reached the end of a line or the end of file marker.
here is what I have so far, and I kind of based it off of code from here
UPDATE: I changed it, but now it just crashes upon hitting enter after text. I know this way is inefficient, and char is not the best for EOF check, but for now I am just trying to get it to return the string. I need it to do it in this fashion and no other fashion. I need the string to be the exact length of the line, and to return a value that is either the newline or EOF int which I believe can still be used in a char value.
This program is in C not C++
char getLine(char **line);
int main(int argc, char *argv[])
{
char *line;
char returnVal = 0;
returnVal = getLine(&line);
printf("%s", line);
free(line);
system("pause");
return 0;
}
char getLine(char **line) {
unsigned int lengthAdder = 1, counter = 0, size = 0;
char charRead = 0;
*line = malloc(lengthAdder);
while((charRead = getc(stdin)) != EOF && charRead != '\n')
{
*line[counter++] = charRead;
*line = realloc(*line, counter);
}
*line[counter] = '\0';
return charRead;
}
Thank you for any help in advance!
You're assigning the result of malloc() to a local copy of line, so after the getLine() function returns it's not modified (albeit you think it is). What you have to do is either return it (as opposed to use an output parameter) or pass its address (pass it 'by reference'):
void getLine(char **line)
{
*line = malloc(length);
// etc.
}
and call it like this:
char *line;
getLine(&line);
Your key problem is that line pointer value does not propagate out of the getLine() function. The solution is to pass pointer to the line pointer to the function as a parameter instead - calling it like getLine(&line); while the function would be defined as taking parameter char **line. In the function, on all places where you now work with line, you would work with *line instead, i.e. dereferencing the pointer to a pointer and working with the value of the variable in main() where the pointer leads. Hope this is not too confusing. :-) Try to draw it on a piece of paper.
(A tricky part - you must change line[counter] to (*line)[counter] because you first need to dereference the pointer to the string, and only then to access a specific character in the string.)
There is a couple of other problems with your code:
You use char as the type for charRead. However, the EOF constant cannot be represented using char, you need to use int - both as the type of charRead and return value of getLine(), so that you can actually distringuish between a newline and end of file.
You forgot to return the last char read from your getLine() function. :-)
You are reallocating the buffer after each character addition. This is not terribly efficient and therefore is a rather ugly programming practice. It is not too difficult to use another variable to track the amount of space allocated and then (i) start with allocating a reasonable chunk of memory, e.g. 64 bytes, so that ideally you will never reallocate (ii) enlarge the allocation only if you need to based on comparing the counter and your allocation size tracker. Two reallocation strategies are common - either doubling the size of the allocation or increasing the allocation by a fixed step.
The way you use realloc is not correct. If it returns NULL then the memory block will be lost.
It is better to use realloc in this way:
char *tmp;
...
tmp = realloc(line, counter);
if(tmp == NULL)
ERROR, TRY TO SOLVE IT
line = tmp;