How to allocate memory for an input string of unknown length?

This is a struct:

typedef struct _friend { char *firstname; char *lastname; char birthdate[9]; } friend; 

I am confused by the way a user enters a string and puts it in the friend structure as firstname (or lastname ). Also, what if a user enters more than 256 characters when I use fgets ? This is what I still have ...

 friend *f = (friend *)malloc(sizeof(friend)); //initialize f pointer to friend char *str; fgets(str,256,stdin); f->firstname = (char*)malloc(sizeof(char)*(strlen(str)+1)); strcpy(f->firstname,str); 
+2
source share
3 answers

Well, since stdin is a buffered input, you can use fgetc to read an input character by character until you hit a new line or EOF. Perhaps you are looking for something like this:

 #include <stdlib.h> #include <string.h> #include <stdio.h> struct friend { char *firstname; char *lastname; char birthdate[9]; }; static char *read_line(FILE *f) { char *r = NULL; char *p = r; char *e = p; int c; while ((c = fgetc(f)) != EOF) { if (p >= e) { size_t l = e > r ? (size_t)(e - r) : 32u; char *x = realloc(r, l); if (!x) { free(r); r = NULL; goto out; } p = x + (p - r); e = x + l; r = x; } if (c != '\n') { *p++ = (char)c; } else { *p++ = '\0'; goto out; } } if (ferror(f) != 0) { free(r); r = NULL; } out: return r; } int main(void) { struct friend f; memset(&f, 0, sizeof(struct friend)); printf("Please enter your first name: "); fflush(stdout); f.firstname = read_line(stdin); if (!f.firstname) goto on_error; printf("Please enter your last name: "); fflush(stdout); f.lastname = read_line(stdin); if (!f.lastname) goto on_error; printf("You first name is: %s\n", f.firstname); printf("Your last name is: %s\n", f.lastname); free(f.firstname); free(f.lastname); return EXIT_SUCCESS; on_error: perror("read_line"); free(f.firstname); free(f.lastname); return EXIT_FAILURE; } 
+2
source

There is no one-time solution to solve this problem. Any particular engineer can use one of several solutions for the same problem based on various criteria:

  • Should a decision be dead stupidly simple?
  • Should I flexibly adapt to a wide range of input lengths?
  • Will the code work only in a limited range of environments where, as you know, there is available memory?
  • Does anyone else need to understand the solution, for example, for routine maintenance?

For a simple solution in a known, adequate memory environment, I can do this:

 char buf [1000]; // for English names, this should be big enough friend f; // not a pointer, but a full struct if (!fgets (buf, sizeof buf, stdin)) { perror ("error reading from stdin"); return; } f.firstname = strdup (buf); // allocates the right size of memory and copies ... // when finished with the structure, deallocate the dynamic strings: free (f.firstname); 

Notice how this almost completely avoids manipulating pointers? (Only strdup() does this, and it carefully encapsulates the necessary operation.) This is a reliable code function with low error rates.

+2
source

Not.

Have a separate buffer for user input. Then, after the user has entered data in this buffer, you will analyze it and determine if it is normal (for example, if it is not an empty string, and if it does not contain any numbers or other strange characters), as well as a strip of excess spaces and etc. If the data is acceptable, determine how long this takes and allocate the correct amount of memory to copy it.

To enter a user into a separate buffer, do not use fgets() . Instead, use fgetc() in a loop so that you can increase the buffer size if necessary. For example, you can start with a small 32-byte buffer, and then double the size of the buffer (using realloc() ) when it is full.

+1
source

Source: https://habr.com/ru/post/979204/


All Articles