I know how to make function with int, double, float with user input inside(im currently using scanf).
int getData(){
int a;
scanf("%i",&a);
return a;
}
but how to make function with string type and user input inside, then we return that value with type string?
A C string is an array of char
terminated by a NUL (zero) byte. Arrays are normally passed around as pointers to the first element. The problem with returning that from the function is that the address pointed to must remain valid beyond the lifetime of the function, which means it needs to be either a static
buffer (which is then overwritten by any subsequent calls to the same function, breaking earlier returned values) or allocated by the function, in which case the caller is responsible for freeing it.
The scanf
you mention is also problematic for reading interactive user input, e.g., it may leave the input in an unexpected state such as when you don't consume the newline at the end of a line the next call to scanf
(maybe in an unrelated function) may surprisingly fail to give the expected result when it encounters the newline.
It is often simpler to read input into a buffer line-by-line, e.g., with fgets
, and then parse the line from there. (Some inputs you may be able to parse without a buffer simply by reading character by character, but such code often gets long and hard to follow quickly.)
An example of reading any string, which may contain whitespace other than the newline, would be something like:
/// Read a line from stdin and return a `malloc`ed copy of it without
/// the trailing newline. The caller is responsible for `free`ing it.
char *readNewString(void) {
char buffer[1024];
if (!fgets(buffer, sizeof buffer, stdin)) {
return NULL; // read failed, e.g., EOF
}
int len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n') {
buffer[--len] = '\0'; // remove the newline
// You may also wish to remove trailing and/or leading whitespace
} else {
// Invalid input
//
// Depending on the context you may wish to e.g.,
// consume input until newline/EOF or abort.
}
char *str = malloc(len + 1);
if (!str) {
return NULL; // out of memory (unlikely)
}
return strcpy(str, buffer); // or use `memcpy` but then be careful with length
}
Another option is to have the caller supply the buffer and its size, then just return the same buffer on success and NULL
on failure. This approach has the
advantage that the caller may decide when a buffer is reused and whether the string needs to be copied or simply read once and forgotten.
Extending Arkku's approach to an unlimited size (in fact it is limited to SIZE_MAX - 1 characters) as input:
#include <stdlib.h>
#include <string.h>
#define BUFFER_MAX (256)
int read_string(FILE * pf, char ** ps)
{
int result = 0;
if (!ps)
{
result = -1;
errno = EINVAL;
}
else
{
char buffer[BUFFER_MAX];
size_t len = 0;
*ps = NULL;
while (NULL != fgets(buffer, sizeof buffer, pf))
{
len += strlen(buffer);
{
void * p = realloc(*ps, len + 1);
if (!p)
{
int es = errno;
result = -1;
free(*ps);
errno = es;
break;
}
*ps = p;
}
strcpy(&(*ps)[len], buffer);
}
if (ferror(pf))
{
result = -1;
}
}
return result;
}
Call it like this:
#include <stdlib.h>
#include <stdlio.h>
int read_string(FILE * pf, char ** ps);
int main(void);
{
char * p;
if (-1 == read_string(stdin, &p)) /* This read from standard input,
still any FILE* would do here. */
{
perror("read_string() failed");
exit(EXIT_FAILURE);
}
printf("Read: '%s'\n", p);
free(p); /* Clean up. */
}