using scanf to read a string and an int separated by / - c

The input consists a string and an integer, which are separated by a '/', like this:
hello/17
And I want to read the input into a string and an int, like this:
char str[20];
int num;
scanf("%s/%d", str, &num); // this how I tried to do it.
I can't seem to make it, any advice?

scanf awaits a whitespace terminated string when it tries to read %s.
Try to specify the forbidden character set directly:
scanf("%19[^/]/%d", str, &num);
You can read more about the formating codes here

You only need to run the following program:
#include <stdio.h>
int main (void) {
char str[20] = {'\0'};
int count, num = 42;
count = sscanf ("hello/17", "%s/%d", str, &num);
printf ("String was '%s'\n", str);
printf ("Number was %d\n", num);
printf ("Count was %d\n", count);
return 0;
}
to see why this is happening. The output is:
String was 'hello/17'
Number was 42
Count was 1
The reason has to do with the %s format specifier. From C99 7.19.6.2 The fscanf function (largely unchanged in C11, and the italics are mine):
s: matches a sequence of non-white-space characters.
Since / is not white space, it gets included in the string bit, as does the 17 for the same reason. That's also indicated by the fact that sscanf returns 1, meaning that only one item was scanned.
What you'll then be looking for is something that scans any characters other than / into the string (including white space). The same section of the standard helps out there as well:
[: matches a nonempty sequence of characters from a set of expected characters (the scanset). The conversion specifier includes all subsequent characters in the format string, up to and including the matching right bracket (]). The characters between the brackets (the scanlist) compose the scanset, unless the character after the left bracket is a circumflex (^), in which case the scanset contains all characters that do not appear in the scanlist between the circumflex and the right bracket.
In other words, something like:
#include <stdio.h>
int main (void) {
char str[20] = {'\0'};
int count, num = 42;
count = sscanf ("hello/17", "%[^/]/%d", str, &num);
printf ("String was '%s'\n", str);
printf ("Number was %d\n", num);
printf ("Count was %d\n", count);
return 0;
}
which gives you:
String was 'hello'
Number was 17
Count was 2
One other piece of advice: never ever use scanf with an unbounded %s or %[; you're asking for a buffer overflow attack. If you want a robust user input function, see this answer.
Once you have it in as a string, you can sscanf it to your heart's content without worrying about buffer overflow (since you've limited the size on input).

Could be like that:
char str[20];
int num;
scanf("%19[^/]%*c%d", str, &num);
%*c reads one character and discards it

Related

Output didn't include all of the characters

I was trying to input a string of characters and only output the last and the first character respectively. Below is the code I'm using.
#include<stdio.h>
int main(){
for(int i=0;i<3;i++){
int n; // length of the string
char string[101];
scanf("%d %s", &n, &string);
fflush(stdin); // sometimes I also use getchar();
printf("%c%c", string[n+1], string[0]);
}
printf("\n");
return 0;
}
I'm using for loop because i wanted to input the string 3 times, but when I ran the code the input isn't what I expected. If I input e.g.
5 abcde
output
a //there's space before the a
can you help me tell where I've gone wrong?
input:
5 abcde
6 qwerty
3 ijk
excpeted output:
ea
yq
ki
Few problems in your code:
In this statement
scanf("%d %s", &n, &string);
you don't need to give & operator with string. An array name, when used in an expression, converts to pointer to first element (there are few exceptions to this rule). Also, the size of string array is 101 characters but if you provide input more than 101 characters, the scanf() end up accessing string array beyond its size. You should restrict the scanf() to not to read more than 100 characters in string array when input size is more than that. (keep the remain one character space is for null terminating character that scanf() adds). For this, you can provide width modifier in the format specifier - %100s.
You are not validating the string length input against the input string from user. What happen, if the input string length is greater than or less than the actual length of input string!
fflush(stdin) is undefined behaviour because, as per standard, fflush can only be used with output streams.
I was trying to input a string of characters and only output the last and the first character respectively.
For this, you don't need to take the length of the string as input from user. Use standard library function - strlen(). This will also prevent your program from the problems that can occur due to erroneous length input from user, if that is not validated properly.
Putting these altogether, you can do:
#include <stdio.h>
#include <string.h>
int main (void) {
for (int i = 0; i < 3 ; i++) {
char string[101];
printf ("Enter string:\n");
scanf("%100s", string);
printf("Last character: %c, First character: %c\n", string[strlen(string) - 1], string[0]);
int c;
/*discard the extra characters, if any*/
/*For e.g. if user input is very long this will discard the input beyond 100 characters */
while((c = getchar()) != '\n' && c != EOF)
/* discard the character */;
}
return 0;
}
Note that, scanf(%<width>s, ......) reads up to width or until the first whitespace character, whichever appears first. If you want to include the spaces in input, you can use the appropriate conversion specifier in scanf() or a better alternative is to use fgets() for input from user.
Line 11: string[n+1] -> string[n-1]

How to get string length using scanf function

How to get the string length without using strlen function or counters, like:
scanf("???",&len);
printf("%d",len);
Input: abcde
Expected output: 5
You can use assignment-suppression (character *) and %n which will store the number of characters consumed into an int value:
int count;
scanf( "%*s%n", &count );
printf( "string length: %d\n", count );
Explanation:
%*s will parse a string (up to the first whitespace characters) but will not store it because of the *.
Then %n will store the numbers of characters consumed (which is the length of the string parsed) into count.
Please note that %n is not necessarily counted for the return value of scanf():
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.
quoted from the man page where you will find everything else about scanf() too.
Use the %n format specifier to get the amount of characters consumed so far and write it to len of type int:
char buf[50];
int len;
if ( scanf("%49s%n", buf, &len) != 1 )
{
// error routine.
}
printf("%d", len);
You can doing this with the n specifier:
%n returns the number of characters read so far.
char str[20];
int len;
scanf("%s%n", &str, &len);
Explanation : Here [] is used as scanset character and ^\n takes input with spaces until the new line encountered. For length calculation of whole string, We can use a flag character in C where nothing is expected from %n, 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 *flag. Here load the variable pointed by the corresponding argument with a value equal to the number of characters that have been scanned by scanf() before the occurrence of %n.
By using this technique, We can speed up our program at runtime instead of using strlen() or loop of O(n) count.
scanf("%[^\n]%n",str,&len);
printf("%s %i",str,len);

Print a middle character of a string

I must write a program in C that can print the middle letter of the string you entered. Spaces () are also calculated, and the number of characters must be odd.
Ex. Input
Hi sussie
--> 9 characters, including space
The output should be s.
I have tried this:
#include <stdio.h>
#include<string.h>
char x[100];
int main(void)
{
printf("Hello World\n");
scanf("%c\n",&x);
long int i = (strlen(x)-1)/2;
printf("the middle letter of the word is %c\n",x[i]);
return 0;
}
and the output always shows the first letter of the word I have entered.
You're only reading the first character from stdin (and incorrectly; you shouldn't be using &).
If you must use scanf, you should use this format:
scanf("%99[^\n]", x);
This is safe and doesn't read past the buffer.
Note that %s wouldn't work here. %s causes scanf to interpret whitespace as the end of the string.
A much better, safer, and easier solution would be to use fgets instead of scanf; fgets is safer and it doesn't require you to change a format string when you change the size of your array:
fgets(x, sizeof(x)-1, stdin);
This eliminates any possible issues with whitespace or buffer overflow.
int main()
{
char arr[1024];
char a;
int i,counter=0;
printf("enter string :: ");
fgets(arr,sizeof(arr),stdin);
for(i=0;i<strlen(arr);i++)
counter++;
for(i=0;i<strlen(arr);i++)
{
if(i==(counter/2))
printf("%c\n",arr[i]);
}
return 0;
}

Calculate length of string without using strlen() function

Having a doubt regarding a very simple C code. I wrote a code to calculate the length of a string without using the strlen function. The code below works correctly if i enter a string with no spaces in between. But if i enter a string like "My name is ---", the length shown is the length of the word before the first white space, which in the example, would be 2. Why is that? Aren't white space and null character two different characters? Please guide me as to how i can change the code so that the entire string length is returned?
char s[1000];
int length = 0;
printf ("Enter string : ");
scanf ("%s", s);
for (int i = 0; s[i] != '\0'; i++)
{
length++;
}
printf ("Length of given string : %d", length);
It is because scanf with %s reads until it finds white space.
from man scanf
Matches a sequence of non-white-space characters; the next pointer
must be a pointer to character array that is long enough to hold the
input sequence and the terminating null byte ('\0'), which is added
automatically. The input string stops at white space or at the maximum
field width, whichever occurs first.
If you want read until \n including white space you can do as below.
scanf("%999[^\n]", s);
Or you could use fgets.
scanf reads the data until "\0" or "\20". So use "fgets" method which reads the data until "\n" (next line) with "stdin",
Example Program:
#include <stdio.h>
int main() {
char s[100];
printf("Input String: ");
fgets(s, sizeof(s), stdin);
printf("\nLength of the string is = %d", printf("%s"), s);
return 0;
}

using scanf("%d ") with a space after the %d

In my c class today I was troubling with the scanf() command, we were just learning pointers and we got a question asking us to get an array, and print it reversed without using the [] for anything but declaring the (int) array. Of course it seems like a piece of cake but not when you accidentally write:
scanf("%d ", arr + i);
Did you notice the space after the %d? Sure did take me a while to figure it out but for some reason that makes loops go crazy, and I wanted you guys to help me (and my teachers) to figure out why does that happen. Example:
#include <stdio.h>
#define LEN 10
void arrayInput(int * arr, unsigned int len);
void arrayReverseOutput(int * arr, unsigned int len);
int main(void)
{
int arr[LEN] = { 0 };
arrayInput(arr, LEN);
arrayReverseOutput(arr, LEN);
system("pause");
return 0;
}
void arrayInput(int * arr, unsigned int len)
{
unsigned int i = 0;
printf("Enter 10 numbers: ");
for (i = 0; i < len; i++)
{
//printf("i = %d \n", i); see what happens when you use this line
scanf("%d ", arr + i);
}
}
void arrayReverseOutput(int * arr, unsigned int len)
{
int i = 0;
printf("The numbers in reverse order: ");
for (i = --len; i >= 0; i--)
{
printf("%d ", *(arr + i));
}
}
I'm really curios to see what's going on with that scanf... it's as if it requires 2 inputs at the first time it runs but somehow still manages to put the inputs in their right position in the array...
Thanks for taking your time to read this <3
A space in the format string tells scanf() to match zero or more whitespace characters, until the match fails. Spaces (' '), newlines('\n'), carriage returns ('\r'), and tabs ('\t') are among the whitespace characters. When a space occurs at the end of a format string, scanf() will try to match whitespace characters from the input until no match is found. But, scanf() can only return when a match fails, or end of file is reached. Thus, in the case of a statement like:
scanf("%d ", arr + i);
the call to scanf() will appear to hang, greedily waiting for more input from the user. Whenever the Enter key is pressed, a newline is sent and matched by scanf(), which is still waiting for a failing match. Or end of file. You can escape such a loop by signalling end of file from the keyboard with Ctrl-D on Linux, or Ctrl-C on Windows.
It is almost always a mistake to terminate a scanf() format string with a space. A newline ('\n') is also a whitespace character, and has the same effect when placed at the end of a format string.
Note that spaces can be used effectively in scanf() format strings. For example:
int retval = scanf(" %c %c", &c1, &c2);
Here, if a previous IO operation has left a newline in the input stream (a not uncommon occurrence), the leading whitespace directs scanf() to read and ignore it. The second space in the format string tells scanf() to expect zero or more whitespace characters between the input characters to be converted. This allows the user to input the characters with an intervening space. Without the added whitespace, if a user entered a b\n, c2 would end up holding the value for a space character, and the b would be left behind in the input stream for the next IO operation to pick up. Also note that scanf() returns the number of successful conversions, allowing the program to check whether the input is as expected. If retval in the above line is anything other than 2, something has gone wrong.

Resources