I understand what is happening when I do this more explicitly using getchar(), putchar() and a while loop; however, I was just wondering is the storing and processing of an entered string the same when the code below is executed (behind the scenes)? Is each character being stored as one element of the array "typed"? How does scanf do this? etc.
#include <stdio.h>
int main(void)
{
char typed[500];
scanf("%[^\tEOF]", &typed);
printf("%s", typed);
return(0);
}
Thanks.
Yes, each character is being stored as one element of the array typed.
Note that your scan string looks for anything except a tab, an 'E', an 'O', or an 'F'; the 'EOF' in the pattern has no connection with EOF returned by getchar() et al on end of file. Also, your code is vulnerable to buffer overflows (hence the succinct comment from knittl) because you don't specify the size of the buffer in the format string. You'd be safer with:
scanf("%499[^\tEOF]", &typed);
Also, the return type of main() is int, not void.
Each element gets saved as elements of array. You should not use & when your variables are already arrays. An array name is already an address.
getchar() has the default delimiter: return key and takes input as character only
while scanf allows various types of input by specifying the format: %s, %d etc
You can also specify the delimiter for scanf (default are space, tab, enter)
In your case, the delimiter is specified as tab or EOF.
Related
i have tried to use k = getchar() but it doesn't work too;
here is my code
#include<stdio.h>
int main()
{
float height;
float k=0;
do
{
printf("please type a value..\n");
scanf("%f",&height);
k=height;
}while(k<0);// i assume letters and non positive numbers are below zero.
//so i want the loop to continue until one types a +ve float.
printf("%f",k);
return 0;
}
i want a if a user types letters or negative numbers or characters he/she should be prompted to type the value again until he types a positive number
Like Govind Parmar already suggested, it is better/easier to use fgets() to read a full line of input, rather than use scanf() et al. for human-interactive input.
The underlying reason is that the interactive standard input is line-buffered by default (and changing that is nontrivial). So, when the user starts typing their input, it is not immediately provided to your program; only when the user presses Enter.
If we do read each line of input using fgets(), we can then scan and convert it using sscanf(), which works much like scanf()/fscanf() do, except that sscanf() works on string input, rather than an input stream.
Here is a practical example:
#include <stdlib.h>
#include <stdio.h>
#define MAX_LINE_LEN 100
int main(void)
{
char buffer[MAX_LINE_LEN + 1];
char *line, dummy;
double value;
while (1) {
printf("Please type a number, or Q to exit:\n");
fflush(stdout);
line = fgets(buffer, sizeof buffer, stdin);
if (!line) {
printf("No more input; exiting.\n");
break;
}
if (sscanf(line, " %lf %c", &value, &dummy) == 1) {
printf("You typed %.6f\n", value);
continue;
}
if (line[0] == 'q' || line[0] == 'Q') {
printf("Thank you; now quitting.\n");
break;
}
printf("Sorry, I couldn't parse that.\n");
}
return EXIT_SUCCESS;
}
The fflush(stdout); is not necessary, but it does no harm either. It basically ensures that everything we have printf()'d or written to stdout, will be flushed to the file or device; in this case, that it will be displayed in the terminal. (It is not necessary here, because standard output is also line buffered by default, so the \n in the printf pattern, printing a newline, also causes the flush.
I do like to sprinkle those fflush() calls, wherever I need to remember that at this point, it is important for all output to be actually flushed to output, and not cached by the C library. In this case, we definitely want the prompt to be visible to the user before we start waiting for their input!
(But, again, because that printf("...\n"); before it ends with a newline, \n, and we haven't changed the standard output buffering, the fflush(stdout); is not needed there.)
The line = fgets(buffer, sizeof buffer, stdin); line contains several important details:
We defined the macro MAX_LINE_LEN earlier on, because fgets() can only read a line as long as the buffer it is given, and will return the rest of that line in following calls.
(You can check if the line read ended with a newline: if it does not, then either it was the final line in an input file that does not have a newline at the end of the last line, or the line was longer than the buffer you have, so you only received the initial part, with the rest of the line still waiting for you in the buffer.)
The +1 in char buffer[MAX_LINE_LEN + 1]; is because strings in C are terminated by a nul char, '\0', at end. So, if we have a buffer of 19 characters, it can hold a string with at most 18 characters.
Note that NUL, or nul with one ell, is the name of the ASCII character with code 0, '\0', and is the end-of-string marker character.
NULL (or sometimes nil), however, is a pointer to the zero address, and in C99 and later is the same as (void *)0. It is the sentinel and error value we use, when we want to set a pointer to a recognizable error/unused/nothing value, instead of pointing to actual data.
sizeof buffer is the number of chars, total (including the end-of-string nul char), used by the variable buffer.
In this case, we could have used MAX_LINE_LEN + 1 instead (the second parameter to fgets() being the number of characters in the buffer given to it, including the reservation for the end-of-string char).
The reason I used sizeof buffer here, is because it is so useful. (Do remember that if buffer was a pointer and not an array, it would evaluate to the size of a pointer; not the amount of data available where that pointer points to. If you use pointers, you will need to track the amount of memory available there yourself, usually in a separate variable. That is just how C works.)
And also because it is important that sizeof is not a function, but an operator: it does not evaluate its argument, it only considers the size (of the type) of the argument. This means that if you do something silly like sizeof (i++), you'll find that i is not incremented, and that it yields the exact same value as sizeof i. Again, this is because sizeof is an operator, not a function, and it just returns the size of its argument.
fgets() returns a pointer to the line it stored in the buffer, or NULL if an error occurred.
This is also why I named the pointer line, and the storage array buffer. They describe my intent as a programmer. (That is very important when writing comments, by the way: do not describe what the code does, because we can read the code; but do describe your intent as to what the code should do, because only the programmer knows that, but it is important to know that intent if one tries to understand, modify, or fix the code.)
The scanf() family of functions returns the number of successful conversions. To detect input where the proper numeric value was followed by garbage, say 1.0 x, I asked sscanf() to ignore any whitespace after the number (whitespace means tabs, spaces, and newlines; '\t', '\n', '\v', '\f', '\r', and ' ' for the default C locale using ASCII character set), and try to convert a single additional character, dummy.
Now, if the line does contain anything besides whitespace after the number, sscanf() will store the first character of that anything in dummy, and return 2. However, because I only want lines that only contain the number and no dummy characters, I expect a return value of 1.
To detect the q or Q (but only as the first character on the line), we simply examine the first character in line, line[0].
If we included <string.h>, we could use e.g. if (strchr(line, 'q') || strchr(line, 'Q')) to see if there is a q or Q anywhere in the line supplied. The strchr(string, char) returns a pointer to the first occurrence of char in string, or NULL if none; and all pointers but NULL are considered logically true. (That is, we could equivalently write if (strchr(line, 'q') != NULL || strchr(line, 'Q') != NULL).)
Another function we could use declared in <string.h> is strstr(). It works like strchr(), but the second parameter is a string. For example, (strstr(line, "exit")) is only true if line has exit in it somewhere. (It could be brexit or exitology, though; it is just a simple substring search.)
In a loop, continue skips the rest of the loop body, and starts the next iteration of the loop body from the beginning.
In a loop, break skips the rest of the loop body, and continues execution after the loop.
EXIT_SUCCESS and EXIT_FAILURE are the standard exit status codes <stdlib.h> defines. Most prefer using 0 for EXIT_SUCCESS (because that is what it is in most operating systems), but I think spelling the success/failure out like that makes it easier to read the code.
I wouldn't use scanf-family functions for reading from stdin in general.
fgets is better since it takes input as a string whose length you specify, avoiding buffer overflows, which you can later parse into the desired type (if any). For the case of float values, strtof works.
However, if the specification for your deliverable or homework assignment requires the use of scanf with %f as the format specifier, what you can do is check its return value, which will contain a count of the number of format specifiers in the format string that were successfully scanned:
ยง 7.21.6.2:
The [scanf] function returns the value of the macro EOF if an input failure occurs
before the first conversion (if any) has completed. Otherwise, the function returns the
number of input items assigned, which can be fewer than provided for, or even zero, in
the event of an early matching failure.
From there, you can diagnose whether the input is valid or not. Also, when scanf fails, stdin is not cleared and subsequent calls to scanf (i.e. in a loop) will continue to see whatever is in there. This question has some information about dealing with that.
So I'm currently learning C programming in preparation for the college semester starting up. Kind of like a "leg up" thing. Anyways, I was doing some practice with comparing strings and putting new values in string arrays using the string copy function, but I'm getting some unexpected behavior that I really can't explain. It always shows a positive result for the string compare check no matter what I enter, and I can't identify where I went wrong. If someone would give me assistance I would greatly appreciate it!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char tVar1[10];
char tVar2[10];
printf("Enter your first test variable: \n");
scanf("%c", &tVar1);
strcpy(tVar2, "yes");
if(strcmp(tVar1, "yes") == 0)
{
printf("It would probably be more effective if you used two different variables.");
}
else
{
printf("Nope, just the same amount of effectiveness.");
}
return 0;
}
%c is used to read a single character value as opposed to a string. When you type in your string on the terminal, only the first character is being read and assigned to tVar1[0]. To read a string from the input stream, you need to use the %s conversion specifier:
scanf( "%9s", tVar1 ); // note no & on tVar1
tVar1 is sized to hold 10 elements, which means we can read at most 9 characters into the buffer (one element must be reserved for the string terminator). The 9 is %9s prevents us from reading more characters into the buffer than it can hold.
Unfortunately, the size must be hard-coded as part of the conversion specifier. There's no way to provide the size as a run-time argument (as there is for printf). There are ways around this - you can build the format string dynamically at runtime, for example - but it's a pain regardless.
Notice that we don't use a & for tVar1 in the scanf call. Under most circumstances, an expression of type "N-element array of T" will be converted to an expression of type "pointer to T", and the value of the expression will be the address of the first element.
To intake a string, change
scanf("%c", &tVar1);
to
scanf("%9s", tVar1);
If you want to read an entire input line(not just a word):
#define MAXLINE 9
char line[MAXLINE + 1];
fgets(line, MAXLINE, stdin);
Note that fgets adds a trailing newline, so you'll need to overwrite that with the null byte.
fgets is also better than scanf, because scanf leaves stdin with a newline, which will cause next input calls to be ``skipped".
When you use %c in scanf it will read only one character. To read a word (text until white space) use %s:
scanf("%9s", tVar1);
The 9 limits the number of characters to read so that you avoid the common butter overflow vulnerability.
When a scanf("%s",s); (one of many ways to get a string which is not perfect) encounters a space in the input, it will try to put it in another variable, right? But what hapens if there is only one variable provided as in this case?
Also what other ways are used to input a string? which is the esiest or best one to use and which one does not give problems like the gets(s); function?
Here is my s_insert function now:
// pointer to pointer needed when you allocate memory in the function
void s_insert(char **string_one){ //inserts string (loss of original data)
*string_one=(char*)malloc(200);
fgets (*string_one,200,stdin);
}
scanf for %s data specification reads characters before first space symbol (' ', '\n' or '\t'). If you want to read string with spaces (more than two words) use fgets function, that is more safe than 'gets' because you can set the maximum number of character that can be allocated in your memory and avoid segmentation fault.
No, it will only try to "put in a variable" when it encounters a % with a suitable conversion specifier in the first argument. That argument is what controls its behavior, not the input.
Having a single %s and multiple words in the input will simply leave the remaining words still in the input buffer, since scanf() will stop when it's done with the single %s, it has nothing more to do then.
It reads its conversion specification string and tries to read input to match that, not the other way around.
Here's what the Beez C guide (LINK) tells about the %[] format specifier:
It allows you to specify a set of characters to be stored away (likely in an array of chars). Conversion stops when a character that is not in the set is matched.
I would appreciate if you can clarify some basic questions that arise from this premise:
1) Are the input fetched by those two format specifiers stored in the arguments(of type char*) as a character array or a character array with a \0 terminating character (string)? If not a string, how to make it store as a string , in cases like the program below where we want to fetch a sequence of characters as a string and stop when a particular character (in the negated character set) is encountered?
2) My program seems to suggest that processing stops for the %[^|] specifier when the negated character | is encountered.But when it starts again for the next format specifier,does it start from the negated character where it had stopped earlier?In my program I intend to ignore the | hence I used %*c.But I tested and found that if I use %c and an additional argument of type char,then the character | is indeed stored in that argument.
3) And lastly but crucially for me,what is the difference between passing a character array for a %s format specifier in printf() and a string(NULL terminated character array)?In my other program titled character array vs string,I've passed a character array(not NULL terminated) for a %s format specifier in printf() and it gets printed just as a string would.What is the difference?
//Program to illustrate %[^] specifier
#include<stdio.h>
int main()
{
char *ptr="fruit|apple|lemon",type[10],fruit1[10],fruit2[10];
sscanf(ptr, "%[^|]%*c%[^|]%*c%s", type,fruit1, fruit2);
printf("%s,%s,%s",type,fruit1,fruit2);
}
//character array vs string
#include<stdio.h>
int main()
{
char test[10]={'J','O','N'};
printf("%s",test);
}
Output JON
//Using %c instead of %*c
#include<stdio.h>
int main()
{
char *ptr="fruit|apple|lemon",type[10],fruit1[10],fruit2[10],char_var;
sscanf(ptr, "%[^|]%c%[^|]%*c%s", type,&char_var,fruit1, fruit2);
printf("%s,%s,%s,and the character is %c",type,fruit1,fruit2,char_var);
}
Output fruit,apple,lemon,and the character is |
It is null terminated. From sscanf():
The conversion specifiers s and [ always store the null terminator in addition to the matched characters. The size of the destination array must be at least one greater than the specified field width.
The excluded characters are unconsumed by the scan set and remain to be processed. An alternative format specifier:
if (sscanf(ptr, "%9[^|]|%9[^|]|%9s", type,fruit1, fruit2) == 3)
The array is actually null terminated as remaining elements will be zero initialized:
char test[10]={'J','O','N' /*,0,0,0,0,0,0,0*/ };
If it was not null terminated then it would keep printing until a null character was found somewhere in memory, possibly overruning the end of the array causing undefined behaviour. It is possible to print a non-null terminated array:
char buf[] = { 'a', 'b', 'c' };
printf("%.*s", 3, buf);
1) Are the input fetched by those two format specifiers stored in the
arguments(of type char*) as a character array or a character array
with a \0 terminating character (string)? If not a string, how to make
it store as a string , in cases like the program below where we want
to fetch a sequence of characters as a string and stop when a
particular character (in the negated character set) is encountered?
They're stored in ASCIIZ format - with a NUL/'\0' terminator.
2) My program seems to suggest that processing stops for the %[^|]
specifier when the negated character | is encountered.But when it
starts again for the next format specifier,does it start from the
negated character where it had stopped earlier?In my program I intend
to ignore the | hence I used %*c.But I tested and found that if I use
%c and an additional argument of type char,then the character | is
indeed stored in that argument.
It shouldn't consume the next character. Show us your code or it didn't happen ;-P.
3) And lastly but crucially for me,what is the difference between
passing a character array for a %s format specifier in printf() and a
string(NULL terminated character array)?In my other program titled
character array vs string,I've passed a character array(not NULL
terminated) for a %s format specifier in printf() and it gets printed
just as a string would.What is the difference?
(edit: the following addresses the question above, which talks about array behaviours generally and is broader than the code snippet in the question that specifically posed the case char[10] = "abcd"; and is safe)
%s must be passed a pointer to a ASCIIZ text... even if that text is explicitly in a char array, it's the mandatory presence of the NUL terminator that defines the textual content and not the array length. You must NUL terminate your character array or you have undefined behaviour. You might get away with it sometimes - e.g. strncpy into the array will NUL terminate it if-and-only-if there's room to do so, and static arrays start with all-0 content so if you only overwrite before the final character you'll have a NUL, your char[10] example happens to have elements for which values aren't specified populated with NULs, but you should generally take responsibility for ensuring that something is ensuring NUL termination.
I am having trouble accepting input from a text file. My program is supposed to read in a string specified by the user and the length of that string is determined at runtime. It works fine when the user is running the program (manually inputting the values) but when I run my teacher's text file, it runs into an infinite loop.
For this example, it fails when I am taking in 4 characters and his input in his file is "ABCDy". "ABCD" is what I am supposed to be reading in and 'y' is supposed to be used later to know that I should restart the game. Instead when I used scanf to read in "ABCD", it also reads in the 'y'. Is there a way to get around this using scanf, assuming I won't know how long the string should be until runtime?
Normally, you'd use something like "%4c" or "%4s" to read a maximum of 4 characters (the difference is that "%4c" reads the next 4 characters, regardless, while "%4s" skips leading whitespace and stops at a whitespace if there is one).
To specify the length at run-time, however, you have to get a bit trickier since you can't use a string literal with "4" embedded in it. One alternative is to use sprintf to create the string you'll pass to scanf:
char buffer[128];
sprintf(buffer, "%%%dc", max_length);
scanf(buffer, your_string);
I should probably add: with printf you can specify the width or precision of a field dynamically by putting an asterisk (*) in the format string, and passing a variable in the appropriate position to specify the width/precision:
int width = 10;
int precision = 7;
double value = 12.345678910;
printf("%*.*f", width, precision, value);
Given that printf and scanf format strings are quite similar, one might think the same would work with scanf. Unfortunately, this is not the case--with scanf an asterisk in the conversion specification indicates a value that should be scanned, but not converted. That is to say, something that must be present in the input, but its value won't be placed in any variable.
Try
scanf("%4s", str)
You can also use fread, where you can set a read limit:
char string[5]={0};
if( fread(string,(sizeof string)-1,1,stdin) )
printf("\nfull readed: %s",string);
else
puts("error");
You might consider simply looping over calls to getc().