How to read into array of strings using gets? - c

I have an array of 15 strings (which don't all have to necessarily be used), and despite reading everywhere that gets should never be used, for some reason I believe it is most convenient for me for this program.
After prompting the user to specify how many rows and columns he wants, to create a matrix, I ask him to enter the matrix values, one row per line at a time. I do this using gets. Simultaneously, I want to scan through the string for the amount of spaces entered to ensure that the user is entering the appropriate amount of numbers that correspond to the amount of columns specified.
At the end I want to print out the second row that I entered.
You can assume rowone and colone are already defined, I just didn't copy that part of the code to save space.
int i=0, rowone, colone, sbar=0, inputs=0;
char matrixone[15][10000];
......
printf("input your matrix\n");
for (i=0;i<rowone;i++){
gets(matrixone[i]);
while(matrixone[i][inputs]!='\n'){
if (mplier[i][inputs] == ' '){
sbar++;
inputs++;
}
else
inputs++;
}
if (sbar>=colone||sbar<colone-1){
printf("Too many/too few inputs per line\n");
main();
}
sbar = 0;
inputs = 0;
}
puts(matrixone[2])
I get warnings when compiling and ultimately not even the chance to input the matrix as "Too many/too few inputs" always pops up.
Any help would be greatly appreciated, thank you!

Infinite loop.
Or more properly, eventually matrixone[i][inputs] accesses way beyond what it was read and maybe beyond the array itself. This leads to undefined behavior (UB).
gets() consumes, but does not save '\n'.
gets(matrixone[i]);
while(matrixone[i][inputs]!='\n'){ // why should this quit?
...
inputs++;
}
Instead, drop gets() as it is dropped from the language for 5 years now, use fgets(), check return value and look for the end of the string as well
if (fgets(matrixone[i], sizeof matrixone[i], stdin) {
while(matrixone[i][inputs] != '\0'){
...
}
}
Suggestion for OP (guessing OP's goal)
char *matrixone[15] = { 0 };
printf("input your matrix\n");
for (i=0;i<min(rowone,15);i++){
buf[1000];
if (fgets( buf, sizeof buf, stdin) == NULL) break;
buf[strcspn(buf, "\n")] = 0;
// qualify buf concerning ' ' , sbar, etc
...
matrixone[i] = strdup(buf);
}

Related

Have to hit enter twice with fgets() in C?

Good Morning, I'm having an issue with some C code where I am forced to hit enter twice each time input is entered if the length of the input is less than the size of 'guess'.
If the length of the input is longer than guess, I only hit enter once, and it functions normally.
I'm not sure what the issue is here, but I provided the function in question that I believe is the source of the problem along with the caller function and main just for context.
Output:
Guess a number: 5555555555
Invalid guess.
Guess a number: 55555555555
Invalid guess.
Guess a number: 555
Invalid guess.
Guess a number:
Invalid guess.
Guess a number: 5555
When I remove the line:
while((ch = getchar()) != '\n' && ch != EOF); // Flush the input buffer
and I extend past the size of the buffer, I receive this output:
Guess a number: 5555555555555555555555555555555555
Invalid guess.
Guess a number: Invalid guess.
Guess a number: Invalid guess.
Guess a number: Invalid guess.
Guess a number: Invalid guess.
Function in Question
char * get_input(char * guess)
{
print_message("guess"); // Prompt user to input a guess
fgets(guess, sizeof (guess), stdin);
if(feof(stdin))
{
printf("error");
exit(EXIT_FAILURE);
}
int ch = 0;
while((ch = getchar()) != '\n' && ch != EOF); // Flush the input buffer
guess[strlen(guess)-1] = '\0'; // Erase new line character
return guess;
}
Caller Function
int make_guess(int *v_guess_count)
{
int result = 0;
bool valid = false;
char guess[10] = {'\0'}; // Buffer to store the guess
do
{
get_input(guess); // Get the input
if(is_valid(guess)) // Check if the input is valid
{
valid = true;
*v_guess_count += 1;
}
}
while (! valid); // Keep asking for input until guess is valid
result = assign_value(guess); // Assign the guess
return result;
}
Main
int main(int argc, char * argv[])
{
int red = 0;
int white = 0;
int v_guess_count = 0;
int target = get_target();
bool game_won = false;
while(game_won == false)
{
red, white = 0; // Reset to zero after each guess
int guess = make_guess(&v_guess_count); // Make a guess. If it's valid, assign it.
printf("guess is: %d\n", guess);
compare(guess, target, &red, &white); // Check the guess with the target number.
print_hints(&red, &white);
if (red == 4)
{
game_won = true;
}
}
printf("You win! It took you %d guesses.\n", v_guess_count);
return 0;
}
You have two somewhat-related problems.
One. In your function
char * get_input(char * guess)
your line
fgets(guess, sizeof (guess), stdin);
does not do what you think it does. You want to tell fgets how big the buffer is, that is, how much memory is pointed to by guess for fgets to read into. But in function get_input, parameter guess is a pointer, so sizeof(guess) is going to be the size of that pointer, not the size of the array it points to. That is, you're going to get a size of probably 4 or 8, not the 10 that array guess up in make_guess is declared as.
To fix this, change your input function to
char * get_input(char * guess, int guess_size)
and change the call in make_guess to
get_input(guess, sizeof(guess));
For more on this point, see this question and also this answer.
Two. Your array guess for reading the user's guess is too small. Instead of making it size 10, make it size 500 or something. That way it will "never" overflow. Don't worry that you're wasting memory by doing that — memory is cheap.
The reason for making the input buffer huge is this: If you make the buffer small, you have to worry about the case that the user might type a too-long line and that fgets might not be able to read all of it. If you make the buffer huge, on the other hand, you can declare that the problem "won't happen" and that you therefore don't have to worry about it. And the reason you'd like to not worry about it it is that worrying about it is hard, and leads to problems like the one you've had here.
To use fgets strictly correctly, while worrying about the possibility that the user's input overflows the buffer, means detecting that it happened. If fgets didn't read all the input, that means it's still sitting there on the input stream, waiting to confuse the rest of your program. In that case, yes, you have to read or "flush" or discard it. That's what your line
while((ch = getchar()) != '\n' && ch != EOF);
tries to do — but the point is that you need to do that only if fgets had the not-big-enough problem. If fgets didn't have the problem — if the buffer was big enough — you don't want to do the flush-the-input thing, because it'll gobble up the user's next line of intended input instead, as you've discovered.
Now, with this said, I have to caution you. In general, a strategy of "make your arrays huge, so you don't have to worry about the possibility that they're not big enough" is not a good strategy. In the general case, that strategy leads to insecure programs and horrible security problems due to buffer overruns.
In this case, though, the problem isn't too bad. fgets is going to do its best not to write more into the destination array than the destination array can hold. (fgets will do a perfect job of this — a perfect job of avoiding buffer overflow — if you pass the size correctly, that is, if you fix problem one.) If the buffer isn't big enough, the worst problem that will happen is that the too-long part of the input line will stay on the input stream and get read buy a later input function, thus confusing things.
So you do always want to think about the exceptional cases, and think about what your program is going to do under all circumstances, not just the "good" ones. And for "real" programs, you do have to strive to make the behavior correct for all cases. For a beginning program like this one, though, I think most people would agree that it's fine to just use a huge buffer, and be done with it.
If you want to go for the extra credit, and perfectly handle the case where the user typed more than the fgets input buffer will hold, you're going to first have to detect that case. The code would look something like:
if(fgets(guess, guess_size, stdin) == NULL)
{
printf("error");
exit(EXIT_FAILURE);
}
if(guess[strlen(guess)-1] != '\n')
{
/* buffer wasn't big enough */
int ch = 0;
while((ch = getchar()) != '\n' && ch != EOF); // Flush the input buffer
/* now print an error message or something, */
/* and ask the user to try again with shorter input */
}
But the point is that you do the while((ch = getchar()) != '\n' && ch != EOF) thing only in the case where fgets failed to read the whole line, not in the case where it succeeded.
If you're still with me, here are two somewhat-important footnotes.
I suggested changing your get_input function to take a second parameter int guess_size, but it turns out a better type to use for the sizes of things is size_t, so a better declaration would be size_t guess_size.
I suggested the test if(guess[strlen(guess)-1] != '\n') to detect that fgets wasn't able to read a full line, but that could fail (pretty badly) in the obscure case where fgets somehow returned an empty line. In that case strlen(guess) would be 0, and we'd end up accessing guess[-1] to see if it was the newline character, which is undefined and wrong. In practice it's probably impossible for fgets to return an empty string (at least, as long as you give it a buffer bigger than 1 to read into), but it's probably easier to write the code in a safer way than to convince yourself that it can't happen. There are a bunch of questions elsewhere on SO about practically and efficiently detecting the case that fgets didn't read a full line successfully, but just now I can't find any of them.

Stopping user input using the enter key in C

I'm trying to write a program that receives strings using fgets, but for some reason I can't get it to go past the user input stage. The input should stop once the user enters a "blank line", ie. the Enter key (\n) but even when this key is pressed the loop continues.
Here's the problematic part of my code:
char array[100][256];
for (int i = 0; array[i] != '\n'; i++)
{
fgets(array[i], 256, stdin);
}
100 and 256 represent the maximum amount of lines and chars expected respectively.
Does anyone know where I went wrong?
Here is your code fixed with minimal changes, explanations in comments. Note that this is not a very good way to solve your problem, long lines for example may not behave as you want (they will get split at several array lines).
char array[100][256];
memset(array, 0, sizeof array); // initialize the memory
int i = 0;
while(i<100) // avoid overflow of lines, also while may be clearer than for loop
{
if(!fgets(array[i], 256, stdin)) break; // detect read failure
if(array[i][0] == '\n') break; // got empty line
// Note [0] above to test first char of line i
++i;
}
if (i==100) { /* too many lines */ }
else if (array[i][0] == 0) { /* read failure */ }
else { /* indexes 0...i-1 contain data, index i contains empty line */ }

How can I regulate input data from user?

I'd like some assistance with understand how inputting data in a program of C works. So far I'm used the java syntax having the convenient try{}catch(){}; clause but I don't see it anywhere on C (or I haven't found it?).
Assuming I have the following array;
float f_array[10];
Normally for me to input data I'd either use a scanf(...); or a file which I can read input from, but for the shake of simplicity let's assume I use scanf(...);
And I have the following;
int i;
for(i = 0; i<10; i++){
scanf("%f", &f_array[i]);
}
Now , my question is how to restrain the user from putting in the input a character or a string or the wrong data type for that matter? Also , should I always try to initialize the array before actually putting values in it?
Note that scanf() returns number of elements successfully read, you can check it:
int success = scanf(...);
if (!success) {
scanf("%*[^\n]%*c"):
// OR while(getchar() != '\n');
}
There is, however, a complex solution. You don't use scanf(), but write a custom input method that processes keystrokes and filters out invalid characters, possibly using getch() (Windows/nCurses). Here's a minimized Windows version:
void readFloat(float* in){
int ch, ind = 0;
char buf[100];
while (1){
ch = getch();
if (ch >= '0' && ch <= '9' || ch == '.') {
buf[ind++] = (char)ch;
putchar(ch);
}
else if (ch == 8) /* Backspace */ {
printf("\b \b");
ind --;
}
}
buf[ind] = '\0';
float ret;
sscanf(buf, "%f", &ret);
return ret;
}
So a possible result of the code:
User input (key presses): 123aaa.bbb456
Program filter (displayed on screen): 123.456
Return value: (float)123.456
Now , my question is how to restrain the user from putting in the input a character or a string or the wrong data type for that matter?
Without dedicated hardware support (say, using a keyboard that does not have letter keys, or some device that gives the user an electric shock to discourage them from hitting the 'A' key) there is no way to restrain a user from entering unwanted data.
Instead, you need to write your code with the ASSUMPTION that the user will enter invalid or poorly formed data, and cope with that. It is true that your code is simpler if you can assume an obedient and tractable user who only gives correct input, but the real world isn't like that.
scanf() - reading and interpreting data directly from stdin doesn't actually work well with such an assumption. The return value from scanf() can give you an indication a problem after the fact (e.g. the return value is number of fields successfully input, or EOF). However, when a problem occurs, scanf() handles it in a way you cannot control. Let's say you code has a
scanf("%f", &f_array[i]);
and the user hits the 'X' followed by the Enter key. scanf() will recognise the 'X' character is waiting to be read, and return immediately. The value it returns will not be 1 (which would indicate success). Even worse, the 'X' will be left to be read by a subsequent call of scanf() and the same will happen again (unless a different format is specified). Which means, if you call scanf() in a loop this way, the same will happen over and over again.
Some folks will tell you to simply find a way to read and discard the character 'X'. The problem with that approach is that there are MANY ways for the user to enter bad inputs, and you need to account for all of them. If the user does something you (or your code) doesn't expect, you get problems (e.g. program hanging waiting for the same input repeatedly, input being used as data when it isn't). You're back where you started.
The more robust approach is to simply read a line of input, and do checks before trying to extract a floating point value from it, such as
char buffer[20];
int got_one = 0;
while (!gotone && fgets(buffer, sizeof buffer, stdin) != NULL)
{
if (check_string(buffer))
{
if (sscanf(buffer, "%f", &f_array[i]) == 1)
{
/* yay - we got a floating point value */
got_one = 1;
}
else
{
fprintf(stderr, "Floating point scanning failed. Try again\n");
}
}
else
{
fprintf(stderr, "Bad data discarded. Try again\n");
}
}
Essentially, this provides several hooks so you can check user input in various ways. If you want to, it can be adapted to discard part of a line, and scan useful data from whatever's left.
The key, however, is that the code does not assume the user is well behaved. It only attempts to read a floating point value after a gauntlet of checks, and still copes if the reading fails.
The code can also be adapted to deal with users who enter data that overflows the buffer (e.g. entering 30 floating point characters on a single line). I'll leave that as an exercise.
Also , should I always try to initialize the array before actually putting values in it?
That depends on the needs of your code, but generally speaking I would not bother.
With approaches like I suggest above, you can avoid a circumstance of using the array (or elements of the array) unless valid data has actually been put into it.
All initialising the array will do is obscure cases where the code doing input (reading from the user) has not properly dealt with bad user input.
give the user some feedback on a per input basis.
process each input and allow user to make corrections as you go.
use "atof()" to do the conversion, but it has a couple of quirks:
it tells you there is an error by returning a value of 0.0
it stops processing if/when it finds an invalid char and returns what it has up to that point
eg. 6.35k gives 6.35 -- this usually works out ok;
otherwise you have to check for invalid chars yourself.
try this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
float f_array[10];
int i;
float input_value;
char temp_string[32];
for(i = 0; i<10; i++){
printf("input a floating point number: ");
scanf("%s",&temp_string[0]);
input_value = atof(temp_string);
while(input_value == 0.0) {
printf("%s is not a valid floating point number\n");
printf("example is 5.6 or 1e32 or 17\n");
printf("try again - input a floating point number: ");
scanf("%s",&temp_string[0]);
input_value = atof(temp_string);
}
f_array[i] = input_value;
printf("String value = %s, Float value = %f\n", temp_string, input_value);
}
/* use the data */
for(i = 0; i<10; i++){
printf("%f\n",f_array[i]);
/* do something */
}
}

How to get 3 chars entered with spaces in scanf into a char array?

I am previously a java programmer, but I'm now doing a C course at university (computer science major).
I need the user to be able to enter 3 chars,the first 2 being numbers, and the last 1 being either 'v' or 'h'.
For example "1 2 v".
I need the user to be able to enter it with the spaces in between each character.
This is my current code:
void manageInput(char box[][width]){
char move[4];
char input[16];
while(1){
scanf("%s", input);
int i = 0;
while(input[i] != 0){
if(input[i] != ' ' && input[i] != "\n"){
move[i] = input[i];
}
i++;
}
printf("%s\n", move);
makeMove(box, move);
printBox(box, height, width);
// TODO
if(move[0] == 'x'){
exit(0);
}
}
}
However if I run it, it works fine when I enter the chars with out spaces like "12v", but If I enter "1 2 v", it will print out "1", call printBox, then print out "2", then print out box again, and so on.
If someone could explain what I'm doing wrong here, I would appreciate it.
If someone could explain what I'm doing wrong here, I would appreciate it.
The short story is: Your code doesn't fulfill your requirements. It simply doesn't do what you want it to do.
Your requirements are:
All fields must be one character. This requirement isn't fulfilled by your code. Your code will mistakenly accept multiple characters per field.
There must be one space (exactly one space?) between the fields. This requirement isn't fulfilled by your code. There might be multiple spaces between the fields, and your code will mistakenly accept that.
In fact, your code invokes undefined behaviour by accessing the move array out of bounds. Consider that as a consequence of one of the above scenarios i might become some value higher than 3. What might happen in this code: move[i] = input[i];?
Your code is also way too complex. All of your functionality can be performed by scanf alone. It's a very powerful function, when you know how to use it correctly... I suggest reading and understanding the manual multiple times, when you have an opportunity. You'll learn a lot!
I notice something you neglected to mention from within the logic you have presented: It's expected that the first field might also be 'x', which corresponds to an exit usecase. This is a bad design; the caller has no opportunity to clean up... but I'll run with it. You really should use return (and return an int value or something, corresponding to error/success) instead.
Let us caste that last paragraph aside, because we can simply consider 'x' to be invalid input (and exit as a result), and I don't want to change the contracts of your functions; I'll leave that to you. The expression described so far appears to be int x = scanf("%1[0123456789]%*1[ ]%1[0123456789]%*1[ ]%1[vh]", a, b, c);.
Note that it is expected that a, b and c will have enough space to store a string of one byte in length. That is, their declaration should look like: char a[2], b[2], c[2];.
Make sure you check the return value (x, in the example)! If x is 3, it's safe to assume that the three variables a, b and c are safe to use. If x is 2, it's safe to assume that a and b are safe to use, and so on... If x is EOF or 0, none of them are safe to use.
By checking the return value, you can reject input that doesn't match that precise pattern, that is:
Fields that aren't exactly one byte in width will be rejected.
Too many or too few spaces will be rejected.
Something else popped up that you have neglected to mention, and it's also present within your code: Chux mentioned that you'll likely be expecting the input to be terminated with a '\n' (newline) character. This can also be implemented in a number of ways using scanf:
scanf("%1*[\n]"); will attempt to read and discard precisely one '\n' character, but there's no way to ensure that was successful. getchar would be more appropriate for that purpose; something along the lines of if (getchar() != '\n') { exit(EXIT_FAILURE); } might make sense, if you wish to ensure that the lines of input are perfectly formed and bomb out when they aren't... #define BOMB_OUT?
scanf("%*[^\n]"); scanf("%*c"); makes more sense; If you're interested in reading one item per line, then it makes sense to discard everything remaining on the line, and then the newline character itself. Note that your program should always tell the user when it's discarding or truncating input. You could also use getchar for this.
void manageInput(char box[][width]){
for (;;) {
char a[2], b[2], c[2];
int x = scanf("%1[0123456789]%*1[ ]%1[0123456789]%*1[ ]%1[vh]", a, b, c);
if (x != 3) {
/* INVALID INPUT should cause an error value to be returned!
* However, this function has no return value (which makes it
* poorly designed)... Calling `exit` gives no opportunity for
* calling code to clean up :(
*/
exit(EXIT_FAILURE);
}
if (getchar() != '\n') {
# ifdef BOMB_OUT
exit(EXIT_FAILURE);
# else
scanf("%*[^\n]");
getchar();
puts("NOTE: Excess input has been discarded.");
# endif
}
char move[4] = { a[0], b[0], c[0] };
printf("%s\n", move);
makeMove(box, move);
printBox(box, height, width);
// TODO
if(move[0] == 'x'){
exit(0);
}
}
}
%s reads a whitespace-delimited string with scanf, so if that's not what you want, it's not the thing to use. %c reads a single character, but does not skip whitespce, so you probably also want a (space) in your format to skip whitespace:
char input[3];
scanf(" %c %c %c", intput, input+1, input+2);
will read 3 non-whitespace characters and skip any whitespace before or between them. You should also check the return value of scanf to make sure that it is 3 -- if not, there was less than 3 characters in your input before an end-of-file was reached.
It's usuall a bad idea to read string via scanf because of potential buffer overflow. Consider using fscanf or better fgets as in
fgets(input, 15, stdin);
Note the extra byte for '\0'.
Also, you're comparing char to string here: input[i] != "\n". It should be input[i] != '\n' instead.
And btw you can just use something like
int x, y;
char d;
scanf("%d%d%c", &x, &y, &d);
This looks like two simple bugs.
You need to use separate indexes for move[] and input[]
int i = 0;
while(input[i] != 0){
if(input[i] != ' ' && input[i] != "\n"){
move[i] = input[i];
}
i++;
}
Imagine input of 1 2 v
input[0] != 0, so we enter the loop
it's not ' ' or '\n' either, so we copy input[0] to move[0]
so far so good
You increment i, and discover that input[1] == ' '
But then you increment i again
You discover that you are interested in input[2] (2) - so you copy it to move[2], rather than move[1]. Oops!
Then to make things worse, you never put an end-of-string character after the last valid character of move[].

C - Making sure user input is of appropriate length

Something that I thought that would be pretty basic has me stumped.
If I have a char array char menuInput[3]; and do fgets(menuInput,3,stdin);, I can easily check if they entered nothing:
if(menuInput[0]=='\n')
{
printf("******You made no selection.******");
}
Or if they entered too many (in this case, more than one) characters:
else if(menuInput[1]!='\n')
{
printf("******Invalid Selection: Please enter a single digit option.******");
break;
}
In that case, the user is entering either no characters, exactly the right amount (one), or too many.
What is giving me trouble is checking when they could either enter no characters, up to n amount, or too many.
If I have char surname[SURNAME_MAX + 1];, and use fgets(surname,SURNAME_MAX + 1,stdin); where SURNAME_MAX is 12, I can't work out how to check whether the input falls within the 'acceptable' range.
I can easily see if the user has inputted anything at all (if surname[0]='\n') and if they have entered exactly 12 characters (with the 13th being the '\n').
I think the crux of things is here is just making sure that, somewhere, surname[SURNAME_MAX + 1] contains '\n', but I don't know how to do that in C.
Regards,
Doug
EDIT: Ok, I'm going with #R Sahu's answer, but am having trouble making it work properly.
I'm expecting, at most, the 12 characters defined by SURNAME_MAX.
This should mean that, by that answer, my array should be surname[SURNAME_MAX+3] ("need at least SURNAME_MAX+2 just to store the newline and the terminating null character")
Then I fgets(surname,SURNAME_MAX + 3,stdin); and then is it supposed to be:
while(strlen(surname)>SURNAME_MAX+2);
{
printf("Input is too long!\n");
printf("Surname (1-12 characters): ");
fgets(surname,SURNAME_MAX + 2,stdin);
}
?
Is that the correct way of implementing the answer?
It looks right to me, but, no matter what I enter, I'm getting the "Input is too long!" message.
EDIT 2: My bad, had some code in the wrong place, all good now.
You said:
What is giving me trouble is checking when they could either enter no characters, up to n amount, or too many.
My suggestion: If you are expecting to see at most N characters, create an array whose size is larger than N+2. You need at least N+2 just to store the newline and the terminating null character, and use fgets on that string. If the length of the string is greater than N+1, then you know they entered too many characters. Detecting whether they entered too few characters is simple. I think you will be able to figure it out.
For finding character in string, you can use strchr method:
char *pch;
pch=strchr(SURNAME,'\n');
if (pch != NULL)
{
// ok we've got \n in string
}
But I'm not sure it is the best way to solve this problem at all.
Suggest separating user input from variable checking/assignment.
First read in user input
char buf[100];
if (fgets(buf, sizeof buf, stdin) == NULL) {
// EOF or IO error occurred.
return;
}
Now qualify input; various methods exist.
int len = strlen(buf);
// lop off potential \n
if (buf > 0 && buf[len-1] == '\n') buf[--len] = 0;
if (len >= sizeof surname) {
// Input too long
return;
}
memcpy(surname, buf, len + 1);

Resources