C string using pointer - c

So, I want to get 5 string inputs from the user using array of pointers to strings. However, I want those strings to have white spaces and hence, I am using the %[^\n]s which accepts the string till a line break occurs. But, this code doesn't work :/ Can someone please explain why??
P.S-> If you use %s in scanf, the code works. But I want white spaces compulsorily. So, please suggest something.
Thanks in advance!
#include<stdio.h>
#include<malloc.h>
void main()
{
char *f[5];
int i;
printf("\nEnter 5 strings:\n");
for(i=0;i<5;i++)
f[i]=malloc(20);
for(i=0;i<5;i++)
scanf("%[^\n]s",f[i]);
printf("The 5 strings are:\n");
for(i=0;i<5;i++)
{
printf("\n%s",f[i]);
}
}

One major problem is the trailing 's' in your format. If you read e.g. this reference you will see that the "%[" format is terminated by the ']' character. When you have that extra 's' in the format, scanf will wait until it matches a literal 's' in the input.
And to skip the ending newline, you can add a leading whitespace in the format and scanf will automatically read and skip all whitespace (including newline) that you don't want in the next iteration of the loop.
You also should limit the length of the input scanf reads, or you might have scanf read more than you have allocated. The limit should be 19 characters (which with the string terminator is 20, like you have allocated).
So the correct format should be " %19[^\n]".
As a side-note, since you allocate all strings equally, why not simply have an array of arrays? Like
char f[5][20];
And if you still decide to go with the pointers, don't forget to free them when you're done. You don't really need it in such a simple case such as your program, but it's better to get the good habits early.

You just need to 'consume' the '\n' character after you've read what you want. Use the following format directive:
"%[^\n]%*c"
Which will read everything up to the newline into the string you pass in, then will consume a single character (the newline) without assigning it to anything (that '*' is 'assignment suppression').

Related

Why is this creating two inputs instead of one

https://i.imgur.com/FLxF9sP.png
As shown in the link above I have to input '<' twice instead of once, why is that? Also it seems that the first input is ignored but the second '<' is the one the program recognizes.
The same thing occurs even without a loop too.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
int randomGen, upper, lower, end, newRandomGen;
char answer;
upper = 100;
lower = 1;
end = 1;
do {
srand(time(0));
randomGen = rand()%(upper + lower);
printf("%d\n", randomGen);
scanf("%s\n", &answer);
}while(answer != '=');
}
Whitespace in scanf format strings, like the \n in "%c\n", tries to match any amount of whitespace, and scanf doesn’t know that there’s no whitespace left to skip until it encounters something that isn’t whitespace (like the second character you type) or the end of input. You provide it with =\n, which fills in the %c and waits until the whitespace is over. Then you provide it with another = and scanf returns. The second time around, the character could be anything and it’d still work.
Skip leading whitespace instead (and use the correct specifier for one character, %c, as has been mentioned):
scanf(" %c", &answer);
Also, it’s good practice to make sure you actually succeeded in reading something, especially when failing to read something means leaving it uninitialized and trying to read it later (another example of undefined behaviour). So check scanf’s return value, which should match the number of conversion specifiers you provided:
if (scanf(" %c", &answer) != 1) {
return EXIT_FAILURE;
}
As has been commented, you should not use the scanf format %s if you want to read a single character. Indeed, you should never use the scanf format %s for any purpose, because it will read an arbitrary number of characters into the buffer you supply, so you have no way to ensure that your buffer is large enough. So you should always supply a maximum character count. For example, %1s will read only one character. But note: that will still not work with a char variable, since it reads a string and in C, strings are arrays of char terminated with a NUL. (NUL is the character whose value is 0, also sometimes spelled \0. You could just write it as 0, but don't confuse that with the character '0' (whose value is 48, in most modern systems).
So a string containing a single character actually occupies two bytes: the character itself, and a NUL.
If you just want to read a single character, you could use the format %c. %c has a few differences from %s, and you need to be aware of all of them:
The default maximum length read by %s is "unlimited". The default for %c is 1, so %c is identical to %1c.
%s will put a NUL at the end of the characters read (which you need to leave space for), so the result is a C string. %c does not add the NUL, so you only need to leave enough space for the characters themselves.
%s skips whitespace before storing any characters. %c does not ignore whitespace. Note: a newline character (at the end of each line) is considered whitespace.
So, based on the first two rules, you could use either of the following:
char theShortString[2];
scanf("%1s", theShortString);
char theChar = theShortString[0];
or
char theChar;
scanf("%c", &theChar);
Now, when you used
scanf("%s", &theChar);
you will cause scanf to write a NUL (that is, a zero) in the byte following theChar, which quite possibly is part of a different variable. That's really bad. Don't do that. Ever. Even if you get away with it today, it will get you into serious trouble some time soon.
But that's not the problem here. The problem here is with what comes after the %s format code.
Let's take a minute (ok, maybe half an hour) to read the documentation of scanf, by typing man scanf. What we'll see, quite near the beginning, is: (emphasis added)
A directive is one of the following:
A sequence of white-space characters (space, tab, newline, etc.; see isspace(3)). This directive matches any amount of white space, including none, in the input.
So when you use "%s\n", scanf will do the following:
skip over any white-space characters in the input buffer.
read the following word up to but not including the next white-space character, and store it in the corresponding argument, followed by a NUL.
skip over any white-space following the word which it just read.
It does the last step because \n — a newline — is itself white-space, as noted in the quote from the manpage.
Now, what you actually typed was < followed by a newline, so the word read at step 2 will be just he character <. The newline you typed afterwards is white-space, so it will be ignored by step 3. But that doesn't satisfy step 3, because scanf (as documented) will ignore "any amount of white space". It doesn't know that there isn't more white space coming. You might, for example, be intending to type a blank line (that is, just a newline), in which case scanf must skip over that newline as well. So scanf keeps on reading.
Since the input buffer is now empty, the I/O library must now read the next line, which it does. And now you type another < followed by a newline. Clearly, the < is not white-space, so scanf leaves it in the input buffer and returns, knowing that it has done its duty.
Your program then checks the word read by scanf and realises that it is not an =. So it loops again, and the scanf executes again. Now there is already data in the input buffer (the second < which you typed), so scanf can immediately store that word. But it will again try to skip "any amount of white space" afterwards, which by the same logic as above will cause it to read a third line of input, which it leaves in the input buffer.
The end result is that you always need to type the next line before the previous line is passed back to your program. Obviously that's not what you want.
So what's the solution? Simple. Don't put a \n at the end of your format string.
Of course, you do want to skip that newline character. But you don't need to skip it until the next call to scanf. If you used a %1s format code, scanf would automatically skip white-space before returning input, but as we've seen above, %c is far simpler if you only want to read a single character. Since %c does not skip white-space before returning input, you need to insert an explicit directive to do so: a white-space character. It's usual to use an actual space rather than a newline for this purpose, so we would normally write this loop as:
char answer;
srand(time(0)); /* Only call srand once, at the beginning of the program */
do {
randomGen = rand()%(upper + lower); /* This is not right */
printf("%d\n", randomGen);
scanf(" %c", &answer);
} while (answer != '=');
scanf("%s\n", &answer);
Here you used the %s flag in the format string, which tells scanf to read as many characters as possible into a pre-allocated array of chars, then a null terminator to make it a C-string.
However, answer is a single char. Just writing the terminator is enough to go out of bounds, causing undefined behaviour and strange mishaps.
Instead, you should have used %c. This reads a single character into a char.

scanf("%[^\n]s",a) with set size of string

So I had a code where I use
scanf("%[^\n]s",a);
and has multiple scanf to take different inputs some being string input. So I understand that scanf("%[^\n]s",a) takes input until new line has been reached, however I was wondering suppose my string can only hold up to 10 characters, then after my string has been filled, but new line hasn't been reached how can i get rid of the extra input before going to new line. I was thinking of doing getchar() until new line has been reached however in order to even check if my 10 spots has been filled I need to use getchar, so doesn't that mess up my next scanf input? Anybody have any other way to do it? Still using scanf() and getchar?
scanf("%[^\n]s",a) is a common mistake; the %[ directive is distinct from the %s directive. What you're asking from scanf is:
A group of non-'\n' characters, followed by...
A literal s character.
Perhaps you intended to write scanf("%[^\n]",a)? Note the deleted s...
You can use the * modifier to suppress assignment for a directive, for example scanf("%10[^\n]", a); followed by scanf("%*[^\n]"); to read and discard up to the next newline and getchar(); to read and discard that newline:
scanf("%10[^\n]", a);
scanf("%*[^\n]"); // read and discard up to the next newline
getchar(); // read and discard that newline
As pointed out, the two format strings could be concatenated to reduce the number of calls to scanf. I wrote my answer this way for the sake of documentation, and I'll leave it as is. Besides, I figure that attempt at optimisation would be negligible; a profiler is likely to indicate much more significant bottlenecks for optimisation in realistic scenarios.
You can use this format to hold the first 10 characters and keep the next lines of input:
scanf("%10[^\n]%*[^\n]",a);
getchar();

Using a char a[10]..but able to put only 5 values?

Using a char a[10]..but able to put only 5 values..and i also want output in string format in single line..i am using following code....
int main(){
char arr[10]={'\0'};
for(int i=0;i<10;i++){
scanf("%c",&arr[i]);
}
printf("%s",arr);
return 0;
}
When you use scanf to read single characters, you have to remember that the newline you enter after each character is also a character. And so it will be read by the scanf calls as well. That means that only every other character you enter will be in the array, and every other character will be a newline. To solve this you have to tell scanf to skip whitespace, which is what the space character before the format in " %c" does.
And because you read ten characters, you don't terminate the string properly so printing the string will most likely lead to undefined behavior as the printf call tries to read beyond the limits of the array in search of the terminator. If you want to read ten characters, you need to make your array 11 characters long.
1) Add space at the beginning of the string format of scanf()
scanf(" %c",&arr[i]);
In your code, the white spaces (hiting ENTER (new line) or SPACE ...) is catched in the scanf("%c",&arr[i]); and you have to avoid the catch of the white spaces by adding space at the beginning of the string format of the scanf
2) And your for loop should be stop at 8 and not at 9
for(int i=0;i<9;i++){
Otherwise you will not have a null terminator for your arr[] string and so you will get undefined behaviour and you can get garbage in the output of printf()
you are setting 5 numbers, but 10 values.
each number you put enter, adds 2 values to your array, the value you entered, and the "enter" key.
this is also the reason the numbers are not int he same line....
BTW, to see this, add some print inside the loop.
The problem is that you enter a character in first scanf then push enter key which is \n.In fact the second scanf is read \n. When you use %c, \n is a Effective character.
You can do like this.
int i;
char arr[11]={'\0'};
for(i=0;i<10;i++){
scanf("\n%c",&arr[i]);//Ignore the first \n
}
printf("%s",arr);

How to limit scanf function in C to print error when input is too long?

I want to limit the scanf function so when I enter for example a char* array <String...> that has more then 30 characters, it will not get it and my output will be error.
I got a hint to use [^n] or something like that but I don't understand how to do it?
I know that I can use scanf("%30s"..) but I don't want the input to be valid and just the error.
Any help would be great.
If you must use scanf then I believe that the best that you can do is use the width specifier with something like: "%31s", as you've already mentioned, then use strlen to check the length of the input, and discard the string and report an error if the input is longer than your limit.
Or possibly skip the strlen by additionally using an %n in your format string, e.g. "%31s%n".
A format string using something like %[^\n] in place of %s simply instructs the function to continue reading until a newline, consuming other whitespace characters along the way. This is useful if you want to allow the input to include whitespace characters.
Review the docs for scanf (here's a copy of the man page).
You could use fgets and sscanf. With fgets you can read a little bit more than 30 characters and then check that you didn't get more than 30 characters.
Or if you really want to use scanf use it with something more than 30 like %32s.
Take a look at this page http://linux.die.net/man/3/sscanf and look for the %n format specifier. I would also recommend looking the sscanf function's return value, which will tell you the number of formatted arguments, as well as the presence of error.
I've used the %n format specifier to help in parsing a string of parameters:
ret = sscanf(line, "%d %d %s %d %d %n", &iLoad, &iScreen, &filename, &stage, &bitmapType, &offset);
The number of chars formatted by the preceding arguments is stored in the variable offset.
You could use getchar in a loop, and count the characters coming in.
int iCharCount = 0;
ch = getchar();
while( ch != EOF ) {
iCharCount++;
if(30 < iCharCount)
{
printf("You have attempted to enter more than 30 characters.\n");
printf("Aborting.");
break;
}
printf( "%c", ch );
ch = getchar();
}
This is a crude example. If it were up to me, I'd allocate a maximum-sized character array, read the whole line in, and then use string utilities to count it, edit it, and so on.
Well in C you can do:
#include <string.h>
...
if(strlen(array_ptr) > 0) error();
Obviously you need a bigger buffer to actually first get the input to it, and then check it's length, so the array could be of e.g. 512 bytes. When you copy strings to it, you need to check that you are getting 0 at the end.
sscanf ,is very good for this kind of thing, but a careful scanf can do the trick here too. You'll want to make sure that you're correctly limiting the number of characters the user can enter, so %31s would mean that 30 chars max + the \0 null terminator (31).
What you're preventing is buffer overflow attacks, which can be extremely effective ways to break sloppily written c programs. Here's an excellent article by Aleph One on BO:
http://insecure.org/stf/smashstack.html

Noticing strange behavior with strings in c

Still in learning mode and may be the following question is a really dumb but I dont have any idea why it is happening..
#include<stdio.h>
int main()
{
/* code to accept string and then a character from stdin */
char str[20], inp;
/*take string from stdin */
printf("string:\n");
scanf("%s",str);
fflush(stdin);
/*input a character */
printf("char:\n");
scanf("%c",&inp);/* code does not reach this point and exits */
}
As mentioned in the comment, after I input the string , for eg. 'strng' the code just exits after printing char: but it does not wait for me input the character. As per my understanding, I have given the size of the array large enough to store the string and if the string entered is smaller than the size of the str array, the compiler will automatically add null character at the end of the string and proceed further. Am I missing something or is there a mistake in my code. Please suggest.
Thanks.
Try removing fflush(stdin);
and put a space before %c in scanf(" %c",&inp);
First of all fflush(stdin) is wrong. Many people recommend it but it is plain and simple undefined.
The problem is caused by scanf leaving \n in the input buffer because "%s" doesn't read whitespace characters. When scanf("%c"..) is reached, it is immediately "satisfied" and fills inp with \n and calls it a day.
The problem is common enough, see these C FAQs:
Scanf interlace
Scanf problems
One (possibly dangerous) solution is to discard \n input:
while((c = getchar()) != '\n' && c != EOF)
;
Another solution might be to use fgets and parse that, or possibly read one character at a time with getc, or maybe tweak the second scamf to discard whitespace characters.
Put a space before the %c in the second scanf like this:
scanf(" %c",&inp)
And as stated by others fflush is defined only for output streams.

Resources