#include<stdio.h>
int main()
{
char str[50]={'\0'};
scanf("%[A-Z]s",str);
printf("%s",str);
return 0;
}
1)
Input:
helloWORLD
output:
2)
Input:
HELLoworlD
output:
HELL
In output 1, i expected the output as "WORLD" but it didnt give any outout.
From output 2, i understood that this is working only if the first few characters are in upper case.
Can you please explain how it actually works?
Interpretation of scansets
When it is given helloWORLD, the conversion specification %[A-Z] fails immediately because the h is not an upper-case letter. Therefore, scanf() returns 0, indicating that it did not successfully convert anything. If you tested the return value, you'd know that.
When it is given HELLoworlD, the scanset matches the HELL and stops at the first o. The format string also attempts to match a literal s, but there's no way for scanf() to report that it fails to match that after matching HELL.
Buffer overflow
Note that %[A-Z] is in general dangerous (as is %s) because there is no constraint on the number of characters read. If you have:
char str[50];
then you should use:
if (scanf("%49[A-Z]", str) != 1)
...some problem in the scan...
Also note that there is a 'difference by one' between the declared length of str and the number in the format string. This is awkward; there's no way to provide that number as an argument to scanf() separate from the format string (unlike printf()), so you may end up creating the format string on the fly:
int scan_upper(char *buffer, size_t buflen)
{
char format[16];
if (buflen < 2)
return EOF; // Or other error indication
snprintf(format, sizeof(format), "%%%zu[A-Z]", buflen-1); // Check this too!?
return scanf(format, buffer);
}
When you do
scanf("%[A-Z]s",str);
It takes input as long as you enter upper-case letters.
And since you set all the array to '\0', printf() will stop printing when it meets one.
Therefore, the first input is blank, and the second is printing until the end of the upper-case string.
Related
I'm teaching myself programming. I read that a string stored in an array of characters can be indexed to extract the nth character.
However, I've been trying to solve this for hours: I realized trying to solve an exercise that I can only access the first character of the array myarray[0]; whereas the rest of index (1,2,3...) values will return nothing. However, if I use the puts function it does return the whole string. Curious thing: strlen is returning the length of my array +1.
example:
int main (void)
{
char myarray[1000]={0};
int i;
fgets(myarray,1000,stdin);
for(i=0;i<strlen(myarray);i++)
printf("myarray[%d]:%c\n",i,myarray[i]);
printf("\n");
printf("strlen:%d\n",strlen(myarray));
puts(myarray);
return 0;
}
input:
6536
output:
strlen:5
myarray[0]:6
myarray[1]:
myarray[2]:
myarray[3]:
myarray[4]:
6536
You are getting this result most probably because of undefined behavior of your program. You are using wrong format specifier to print a size_t type (strlenreturn size_t type). Change the format specifier to %zu.
Also note that in for loop you need to declare i as size_t type.
Here is the fixed code: http://ideone.com/0sMadV
fgets writes a newline character \n into the buffer to represent newlines in the input stream. Thus strlen returns 5.
The actual output is :
6536
myarray[0]:6
myarray[1]:5
myarray[2]:3
myarray[3]:6
myarray[4]:
strlen:5
6536
As you can see, myarray[4] stores the newline (due to fgets). Also, it would be better to calculate strlen once by placing it above the loop, instead of in every iteration.
From here:
char *fgets(char *restrict s, int n, FILE *restrict stream);
The fgets() function shall read bytes from stream into the array
pointed to by s, until n-1 bytes are read, or a is read and
transferred to s, or an end-of-file condition is encountered. The
string is then terminated with a null byte.
A simple way is to for strlen(var)-1. Another way is to remove the newline with null terminating character:
if (myarray[length - 1] == '\n')
myarray[length - 1] = '\0';
where length = strlen(myarray);
The strlen counts the '\n' at the end of the string. You can "fix" it with strtok:
strtok(myarray, "\n");
This is my target:
input: string with mixed ASCII characters (uppercase, lowercase, numbers, spaces)
output: string with only uppercase characters
I have this:
#include <stdio.h>
void csere(char s[]){
int i;
for(i=0; s[i]!='\0'; i++){
if('a'<=s[i] && s[i]<='z'){
s[i]-=32;
}
printf("%c", s[i]);
}
}
void main(){
char s[1];
scanf("%s", &s);
csere(s);
}
My problem is:
The function stops at the first 'space' character in the string.
I tried to change the s[i] != '\0' in the 'for' part for i <
strlen(s) or just for s[i], but I still get the same result.
Example: qwerty --> QWERTY, but qwe rty --> QWE
(smaller problem: The program only accepts strings with length less than 12, if i change the 1 to 0 in main function.)
Thanks for help. Sorry for bad English.
scanf only scans non-whitespace characters with the %s modifier. If you want to read everything on a string you should use fgets with stdin as the third parameter:
fgets(s, sizeof s, stdin);
If you really need to use scanf for homework or something, you should use something like:
scanf("%128[^\n]", s);
Also, take note you are not allocating enough space for the string, the fact that it has not crashed is just pure coincidence... you should allocate the space on your array:
char s[128]; // change 128 for max string size
Actually, the fgets() usage I wrote earlier would only read 1 character (including the terminator string) since you only put 1 character on the array... change the array size and it should work.
You could also just use toupper() on ctype.h, but I guess this is some kind of homework or practice.
Furthermore, if you are allowed to use pointers, this would be a shorter (and probably more performant although that'd have to be tested... compilers are good these days :-) ) way to convert to uppercase (notice though it changes your original char array, and doesn't print it, although that'd be easy to modify/add, I'll leave it to you):
void strupper(char *sptr) {
while (*sptr) {
if ((*sptr >= 'a' ) && (*sptr <= 'z')) *sptr -= 32;
sptr++;
}
}
From scanf
s
Matches a sequence of bytes that are not white-space characters. The application shall ensure that the corresponding argument is a pointer to the initial byte of an array of char, signed char, or unsigned char large enough to accept the sequence and a terminating null character code, which shall be added automatically.
This means, with %s, scanf reads a string until it encounters the first white space character. Therefore, your function converts the given string only to the first space.
To the second (smaller) problem, the array s must be large enough for the entire string given. Otherwise, you overwrite the stack space and get undefined behaviour. If you expect larger strings, you must increase the size of s, e.g.
char s[100];
While I could use strings, I would like to understand why this small example I'm working on behaves in this way, and how can I fix it ?
int ReadInput() {
char buffer [5];
printf("Number: ");
fgets(buffer,5,stdin);
return atoi(buffer);
}
void RunClient() {
int number;
int i = 5;
while (i != 0) {
number = ReadInput();
printf("Number is: %d\n",number);
i--;
}
}
This should, in theory or at least in my head, let me read 5 numbers from input (albeit overwriting them).
However this is not the case, it reads 0, no matter what.
I understand printf puts a \0 null terminator ... but I still think I should be able to either read the first number, not just have it by default 0. And I don't understand why the rest of the numbers are OK (not all 0).
CLARIFICATION: I can only read 4/5 numbers, first is always 0.
EDIT:
I've tested and it seems that this was causing the problem:
main.cpp
scanf("%s",&cmd);
if (strcmp(cmd, "client") == 0 || strcmp(cmd, "Client") == 0)
RunClient();
somehow.
EDIT:
Here is the code if someone wishes to compile. I still don't know how to fix
http://pastebin.com/8t8j63vj
FINAL EDIT:
Could not get rid of the error. Decided to simply add #ReadInput
int ReadInput(BOOL check) {
...
if (check)
printf ("Number: ");
...
# RunClient()
void RunClient() {
...
ReadInput(FALSE); // a pseudo - buffer flush. Not really but I ignore
while (...) { // line with garbage data
number = ReadInput(TRUE);
...
}
And call it a day.
fgets reads the input as well as the newline character. So when you input a number, it's like: 123\n.
atoi doesn't report errors when the conversion fails.
Remove the newline character from the buffer:
buf[5];
size_t length = strlen(buffer);
buffer[length - 1]=0;
Then use strtol to convert the string into number which provides better error detection when the conversion fails.
char * fgets ( char * str, int num, FILE * stream );
Get string from stream.
Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
A newline character makes fgets stop reading, but it is considered a valid character by the function and included in the string copied to str. (This means that you carry \n)
A terminating null character is automatically appended after the characters copied to str.
Notice that fgets is quite different from gets: not only fgets accepts a stream argument, but also allows to specify the maximum size of str and includes in the string any ending newline character.
PD: Try to have a larger buffer.
The man page states that the signature of sscanf is
sscanf(const char *restrict s, const char *restrict format, ...);
I have seen an answer on SO where a function in which sscanf is used like this to check if an input was an integer.
bool is_int(char const* s) {
int n;
int i;
return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}
Looking at !s[n] it seems to suggest that we check if sscanf scanned the character sequence until the termination character \0. So I assume n stands for the index where sscanf will be in the string s when the function ends.
But what about the variable i? What does it mean?
Edit:
To be more explicit: I see the signature of sscanf wants a pointer of type char * as first parameter. A format specifier as seconf parameter so it knows how to parse the character sequence and as much variables as conversion specifiers as next parameters. I understand now that i is for holding the parsed integer.
Since there is only one format specifier, I tried to deduce the function of n.
Is my assumption above for n correct?
Looks like the op has his answer already, but since I bothered to look this up for myself and run the code...
From "C The Pocket Reference" (2nd Ed by Herbert Shildt) scanf() section:
%n Receives an integer of value equal to the number of characters read so far
and for the return value:
The scanf() function returns a number equal to the number of the number of fields
that were successfully assigned values
The sscanf() function works the same, it just takes it's input from the supplied buffer argument ( s in this case ). The "== 1" test makes sure that only one integer was parsed and the !s[n] makes sure the input buffer is well terminated after the parsed integer and/or that there's really only one integer in the string.
Running this code, an s value like "32" gives a "true" value ( we don't have bool defined as a type on our system ) but s as "3 2" gives a "false" value because s[n] in that case is "2" and n has the value 2 ( "3 " is parsed to create the int in that case ). If s is " 3 " this function will still return true as all that white space is ingored and n has the value of 3.
Another example input, "3m", gives a "false" value as you'd expect.
Verbatim from sscanf()'s man page:
Conversions
[...]
n
Nothing is expected; instead, the number of characters
consumed thus far from the input is stored through the next pointer,
which must be a pointer to int. This is not a
conversion, although it can be suppressed with the * assignment-suppression character. The C
standard says: "Execution of
a %n directive does not increment the assignment count returned at the completion of
execution" but the Corrigendum seems to contradict this. Probably it is wise not
to make any assumptions on the effect of %n conversions on the return value.
I would like to point out that the original code is buggy:
bool is_int(char const* s) {
int n;
int i;
return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}
I will explain why. And I will interpret the sscanf format string.
First, buggy:
Given input "1", which is the integer one, sscanf will store 1 into i. Then, since there is no white space after, sscanf will not touch n. And n is uninitialized. Because sscanf set i to 1, the value returned by sscanf will be 1, meaning 1 field scanned. Since sscanf returns 1, the part of the expression
sscanf(s, "%d %n", &i, &n) == 1
will be true. Therefore the other part of the && expression will execute. And s[n] will access some random place in memory because n is uninitialized.
Interpreting the format:
"%d %n"
Attempts to scan a number which may be a decimal number or an integer or a scientific notation number. The number is an integer, it must be followed by at least one white space. White space would be a space, \n, \t, and certain other non-printable characters. Only if it is followed by white space will it set n to the number of characters scanned to that point, including the white space.
This code might be what is intended:
static bool is_int(char const* s)
{
int i;
int fld;
return (fld = sscanf(s, "%i", &i)) == 1;
}
int main(int argc, char * argv[])
{
bool ans = false;
ans = is_int("1");
ans = is_int("m");
return 0;
}
This code is based on, if s is an integer, then sscanf will scan it and fld will be exactly one. If s is not an integer, then fld will be zero or -1. Zero if something else is there, like a word; and -1 if nothing is there but an empty string.
variable i there means until it has read an integer vaalue.
what are you trying to ask though? Its not too clear! the code will (try to ) read an integer from the string into 'i'
Suppose you have a string which is NOT null terminated and you know its exact size, so how can you print that string with printf in C? I recall such a method but I can not find out now...
There is a possibility with printf, it goes like this:
printf("%.*s", stringLength, pointerToString);
No need to copy anything, no need to modify the original string or buffer.
Here is an explanation of how %.*s works, and where it's specified.
The conversion specifications in a printf template string have the general form:
% [ param-no $] flags width [ . precision ] type conversion
or
% [ param-no $] flags width . * [ param-no $] type conversion
The second form is for getting the precision from the argument list:
You can also specify a precision of ‘*’. This means that the next argument in the argument list (before the actual value to be printed) is used as the precision. The value must be an int, and is ignored if it is negative.
— Output conversion syntax in the glibc manual
For %s string formatting, precision has a special meaning:
A precision can be specified to indicate the maximum number of characters to write; otherwise characters in the string up to but not including the terminating null character are written to the output stream.
— Other output conversions in the glibc manual
Other useful variants:
"%*.*s", maxlen, maxlen, val will right-justify, inserting spaces before;
"%-*.*s", maxlen, maxlen, val will left-justify.
You can use an fwrite() to stdout!
fwrite(your_string, sizeof(char), number_of_chars, stdout);
This way you will output the first chars (number defined in number_of_chars variable ) to a file, in this case to stdout (the standard output, your screen)!
printf("%.*s", length, string) will NOT work.
This means to print UP TO length bytes OR a null byte, whichever comes first. If your non-null-terminated array-of-char contains null bytes BEFORE the length, printf will stop on those, and not continue.
printf("%.5s", pointerToNonNullTerminatedString);
The string length will be 5.
#include<string.h>
int main()
{
/*suppose a string str which is not null terminated and n is its length*/
int i;
for(i=0;i<n;i++)
{
printf("%c",str[i]);
}
return 0;
}
I edited the code,heres another way:
#include<stdio.h>
int main()
{
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/
return 0;
}