While you have found the nul-terminator issue that was causing initial problems, there are a couple of other issues you will want to address when taking input. Your choice of fgets
is a good one. However, like all line-oriented input functions, it will read up to and including the newline ('\n'
) into your buffer. This leaves your buffer with an embedded '\n'
at the end. You will want to remove or trim the trailing newline as part of your input routine. Otherwise, this will cause problems later on (imagine calling strcat
to add to the buffer later).
Handling removal is straight forward. To help yourself in this task, when you call strlen
in your function, save the results. This will prevent having to make repeated calls to strlen
in your function. With the length known, you can perform your test to check if additional characters remain unread, and following that test, you know whether there is a '\n'
located at buffer[len-1]
or not. If one is present, just overwrite the '\n'
with the nul-terminating character to remove the trailing newline. e.g.
buf[--length] = 0; /* remove newline, decrement length */
Decrementing the length at the same time, updates the length to the current length reflecting the removal of the newline. Since you have gone to the trouble to compute the length of the string taken as input, it would be nice to make the length available to the calling function without having to repeat the strlen
call.
Since you are returning a pointer to the buffer holding the input, one way to do this is to simply pass a pointer for the length as a parameter to your input function, and update the pointer value with the length of the string. That way the length is computed only once and it is available to the calling function immediately upon the function return.
In addition, you can make use to the strchr
function to check for your choice of invalid characters in the input. If there are multiple values you would like to consider invalid, or if they change depending on the input your are taking, you can pass a string containing each of the characters as a parameter to your function. Another consideration is presented if an invalid character is found. While your error checking is fine, if you do find an invalid character, you can set your buffer to empty-string by setting the first character in the string to the nul-terminating character.
You can add flexibility to your input function by passing the prompt as a parameter to the function as well. That way, instead of having a function that prompts for and returns a filename, you have a function that can prompt for any input. The general idea is to get away from hard-coding values in your function and, instead, pass values that change as parameters to your function. You can do the same with your character limit as well. So instead of having a function limited to prompting for/reading a filename of 49-chars, you have a general input function that can read any length string into an adequately size character array.
Putting those pieces together, you could greatly increase the flexibility of your input function. The following is a short example function that passes changing information as parameter. Look it over and let me know if you have any questions. Hopefully the example will provide you with a few of the general considerations to consider when writing any function in C. Good luck with your coding:
char *getstr_input (char *buf, size_t max, size_t *n, const char *prompt)
{
if (!buf) return NULL;
if (*prompt) printf ("%s : ", prompt); /* prompt */
if (!fgets (buf, max, stdin)) return NULL; /* read input */
if (!(*n = strlen (buf))) return NULL; /* test strlen */
if (*n + 1 == max && buf[*n-1] != '\n') { /* test short-read */
fprintf (stderr, "warning: short-read, characters remain unread.\n");
}
else /* remove trailing '\n' */
buf[--*n] = 0;
if (strchr (buf, '%')) { /* validate unwanted characters */
fprintf (stderr, "error: invalid character in string.\n");
*buf = *n = 0; /* set to empty-string, 0 length */
return NULL;
}
return buf;
}
Where 'buf'
is adequately sized to hold 'max'
characters, that on return contains 'n'
characters (not including the nul-terminating character) and for which the user is prompted with 'prompt'
to input. A short test program could be:
#include <stdio.h>
#include <string.h>
enum { MAX = 50 }; /* create a constant 50, adjust as desired */
int main (void) {
char fname[MAX] = {0};
size_t len = 0;
getstr_input (fname, MAX, &len, "enter a filename");
printf ("\n filename : %s\n length : %zu\n\n", fname, len);
return 0;
}
Example Use/Output
$ ./bin/fgets_prompt
enter a filename : 12345678
filename : 12345678
length : 8
$ ./bin/fgets_prompt
enter a filename : 12345%6
error: invalid character in string.
filename :
length : 0