My program requires the user to enter input consisting of 16 characters (excluding null terminator) twice then store it in separate strings. Here is my current code:
void takeInput16(char *inputStr, int size){
do{
printf("Enter a string of length 16\n");
fgets(inputStr, size, stdin);
} while(!(inputStr[size - 2] == '\n' && inputStr[size - 3] != '\0'));
}
int main(){
char *num1 = malloc(18 * sizeof(char));
char *num2 = malloc(18 * sizeof(char));
takeInput16(num1, 18);
takeInput16(num2, 18);
return 0;
}
This works fine for detection of input of less than 16 characters however it does not handle input being longer than 16 characters as it causes multiple calls to fgets to occur.
My question is, how can I safely take input in C and ensure it is of a certain size in terms of characters (I want to reject input which is too long rather than simply truncating the extra characters)
CodePudding user response:
Your code does not properly check the input: the null byte should be at offset size - 1
and the newline at offset size - 2
, but most importantly you should check that fgets()
did not fail and that the length of the input is size - 1
.
Here is a modified version:
#include <stdio.h>
#include <string.h>
void takeInput(char *inputStr, int size) {
for (;;) {
printf("Enter a string of length %d\n", size - 2);
if (!fgets(inputStr, size, stdin)) {
perror("input error");
abort();
}
if (strlen(inputStr) < size - 1) {
printf("input too short, need %d bytes\n", size - 2);
continue;
}
if (inputStr[size - 2] != '\n') {
int c;
/* read and discard the rest of the input line */
while ((c = getchar()) != EOF && c != '\n')
continue;
printf("input too long, need %d bytes\n", size - 2);
continue;
}
inputStr[size - 2] = '\0'; /* strip the newline */
break;
}
}
int main() {
char *num1 = malloc(18 * sizeof(char));
char *num2 = malloc(18 * sizeof(char));
takeInput(num1, 18);
takeInput(num2, 18);
printf("num1: %s\n", num1);
printf("num2: %s\n", num2);
free(num1);
free(num2);
return 0;
}
CodePudding user response:
Assuming the input is ASCII, you can read the characters one by one using fgetc
until buffer is full or \n
is detected. If buffer is full, keep reading until \n
is detected, as the example below.
Note that this example will read up to 4 characters when size is 5, it needs room for the null-terminating character at the end. The EOF
check is not necessary for stdin
but you might as well put it there in case input is redirected.
int takeInputx(char* buf, int bufsize)
{
buf[bufsize - 1] = '\0';
for (int i = 0; ; i )
{
int ch = fgetc(stdin);
int end = (ch == '\n' || ch == EOF);
if (i < bufsize - 1)
buf[i] = end ? '\0' : (char)ch;
if (end)
return i;
}
return 0;
}
int main()
{
int size = 5;
char* num1 = malloc(size * sizeof(char));
for (int i = 0; i < 3; i )
{
int res = takeInputx(num1, size);
printf("%s, string len %d, exceeds max size? %d\n",
num1, strlen(num1), res >= size);
}
free(num1);
return 0;
}