what is the %2d in scanf - c

I know the meaning of this statement
scanf("%d",&x);
But what does this statement do
scanf("%2d",&x);
I tried searching for this, but could not find an answer. I want to know what happens internally also.

That's two digits number:
int n = 0;
scanf ("%2d", &n);
printf ("-> %d\n", n);
12
-> 12
88657
-> 88

The number right after the '%' sign and right before the type of data you wish to read represents the maximum size of that specific type of data.
As you are reading an integer (%2d), it will only allow an integer up to two digits long. If you were to read a 50 characters long array, you should use %49s (leaving one for the null terminating byte). It is the same idea.
int number = 0;
scanf("%2d", &number);
printf("%d", number);
If the user passed 21 for the scanf() function, the number 21 would be stored in the variable number. If the user passed something longer than 21, i.e. 987, only the first 2 digits would be stored - 98.

Related

Input of multiple integers at once for dynamic array in C

My input consists of a sequence of integers, that need to be saved in a dynamic array. The number of integers is the first integer of the sequence. For example: 3 23 7 -12 or 5 -777 3 56 14 7
The sequence is ONE input.
How can i scan such an input?
For scanf("%i %i %i ...",)i need to know the amount of integers in advance, which i dont.
Use multiple scanf calls. First read the count, then read the values in a loop.
int count;
scanf("%i", &count);
int values[count];
for (int i=0; i<count; i++) {
scanf("%i", &values[i]);
}
Note that this doesn't include error checking for invalid values.
You can do it with a do-while loop:
int status = 0;
do {
status = scanf("%d", &placeToStoreVariablesAt);
} while(status);
Note that scanf() returns number of elements of correct type entered. If a char is entered, status becomes 0 and therefore program exits loop.

C's scanf function. If a width modifier is use, Eg: %5d. How to prevent any excess number type in by user from being read into the next %d specifier?

I would like the user to key in 2 numbers and use scanf function to read in these two numbers into 2 int variables.
int num, num2;
scanf("%5d %d", &num, &num2);
printf("num = %d\n", num);
printf("num2 = %d\n", num2);
If the user key in the first number with the number of digits greater than 5, any excess digits should be discarded.
Eg: If user enters the following at the prompt
% 12345678 222<Enter>
num = 12345
num2 = 678
What I want is:
num = 12345
num2 = 222
I have modified my scanf function pattern to the following:
scanf("%5d %*[0123456789] %d", &num, &num2 );
This seems to solve the problem, if the first number that the user input in more than 5 digit, but if it is 5 digit or less, this format specifier will discard the second number that the user key in, and a third number need to be key in.
Eg: If the user key the following in the command prompt:
% 12345 222 333 <Enter>
num = 12345
num2 = 333
What I want is:
num = 12345
num2 = 222
Any C professional out there can offer a solution, thanks.
The problem is the space before the scanset and also that the scanset must match to move to the next field. Try this:
scanf("%5d%*[0123456789]", &num);
scanf("%d", &num2);
2 scanf invocations are required because the scanset will not match if the first number is 5 digits or less.
(And you must check the return values of both)
The goal here strikes me as questionable. Silently ignoring user input, even if you consider it incorrect, is highly confusing for the user and can end up compounding errors.
Anyway, you're not going to be able to do that with a single call to scanf. So you need to do it pieces: use scanf to read at most five characters as an integer. Then getc the next character; if it's a digit (see isdigit()), discard it and repeat. Finally, scanf the second integer.

How to fix segmentation fault when trying to scanf a string?

I'm trying to make a program that writes to a file every combination of letters formed from a given phone number. I'm fairly positive it's giving the segfault where I scanf the name of the file the user wants to write to (in main) because I've put in printf tests and they don't print. For some reason, before adding in my recursive functions it doesn't give me a segfault but after adding them it does.
const char letters[8][5] = {"ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"};
int main()
{
int userNum[7];
char userFile[25];
printf("Please enter the phone number you want to process with no added
characters or spaces: ");
scanf("%d", &userNum);
printf("Enter the file name (including extension and less than 25
characters) that you would like to write to.\n");
scanf("%s", userFile); //This is where I think the seg fault is happening
printf("Test"); //Because this doesn't print
FILE* file_ptr;
char fileName[17];
sprintf(fileName, "%s", userFile);
file_ptr = fopen(fileName, "w");
findWordsHelper(userNum, 7);
}
//Adding this function and the one after is what made the program start
//giving said seg fault
void findWords(int userNum[], int digit, char words[], int n)
{
printf("Test. n = %d", n);
int i;
if(digit == n)
{
printf("%s ", words);
return;
}
for(i = 0; i < strlen(letters[userNum[digit]]); i++)
{
words[digit] = letters[userNum[digit]][i];
findWords(userNum, digit+1, words, n);
if(userNum[digit] == 0 || userNum[digit] == 1)
{
return;
}
}
}
void findWordsHelper(int userNum[], int n)
{
printf("test");
char result[n+1];
result[n] = '\0';
findWords(userNum, 0, result, n);
}
I'm not in an environment that I can test but I see a few things. First off, your printf test isn't printing because if has no new line character. If you're not going to put one in, call fflush. E.g
printf("test");
fflush(stdout);
Second, your use of scanf to read in the phone number shows a bit of misunderstanding of how scanf will treat input as an integer. You don't need an array of 7 ints for this because you've simply instructed for the input to be no extra characters. So, a phone number like 345-6789 is input as 3456789 which will be read as a single int: i.e 3 million, 4 hundred 56 thousand, 7 hundred 89. This will be read into a single integer. I know you want to treat them as separate numbers, but scanf will treat them as 1 number when not separated by whitespace. To read into a single int, this would suffice:
...
int phoneNumber;
scanf("%d", &phoneNumber); // <--- notice the & operator
EDIT
I was reading over the manual page for scanf() and when the %s specifier is used, it should insert a null-character into the string. So, the part directing to check the return and ensure a '\0' character is placed there is not applicable.
EDIT 2
I had a moment this morning and had to figure this out. I think I've got it. Something in the function findWords() looked a bit suspect and compiling, seg-faulting, and looking at the core file showed it to be the case. It's this line in that function
for(i = 0; i < strlen(letters[userNum[digit]]); i++)
Specifically, it is the call to strlen() with the result of using userNum[] to index into letters[]. As myself, and others, have indicated, scanf() isn't going to read a "phone number" such as 3456789 (input as such) into 7 different integer values. It is read as a single int and it's going to be read into userNum[0] (and guess what? digit = 0 when the segfault occurs). This is no surprise, the letters array does not contain 3 million, 4 hundred 56 thousand, 7 hundred 89 indecies. (Assuming the number entered is what I wrote.)
As mentioned by Jasen (I think), ints don't really work well for phone numbers. At the very least, you'll have to develop a different manner of breaking apart the phone number to use as an index.
First of all, lack of printf output does not indicate that the program did not execute past that point, as the output is probably buffered.
You can either do fflush(stdout) immediately after a printf call, or use setvbuf with a null argument to force unbuffering.
Second, in your recursive function, each call results in calling itself up to the number of iterations in your for loop. I suspect there are logic errors there and the number of recursive calls may just explode.
Third, you definitely have a logic problem here:
int userNum[7];
...
scanf("%d", &userNum);
Looks like you are expecting that if a user enters "1234567", that each userNum[i] contains one of the digit, but that's not what's happening.
scanf would treat the argument as a pointer to an int, e.g. on a 32-bit CPU, it would put the integer value 1234567 into the first 4 bytes of "userNum". In fact, this could cause a segfault right there if the CPU cannot write to an integer (whether 16 or 32 bits) to an unaligned address. As userNum is actually an array, it may or may not be aligned suitable for an integer.
int main() {
int userNum[7];
char userFile[25];
printf("Please enter the phone number you want to process with no added"
" characters or spaces: ");
printf("Enter the file name (including extension and less than 25 "
" characters) that you would like to write to.\n");
scanf("%s", userFile); //This is where I think the seg fault is happening
should be :
scanf("%24s",userfile);
that puts a limit of 24 chars on what is read.
char fileName[17];
sprintf(fileName, "%s", userFile);
However userfile could be 24 long... and that can only fit 16, so it should be.
sprintf(fileName, "%.16s", userFile);
which chops off any overflow.

Parsing number into digits with scanf()

I want to type in a number that is 10 digits long, then put the digits into an array. But for some reason, I get this random 2-digit numbers that seem to have nothing to do with my input (??).
char number[10]; //number containing 10 digits
scanf("%s",number); //store digits of number
printf("%d\n",number[0]); //print the 1st digit in the number
printf("%d\n",number[1]); //print the 2nd digit in the number
Here is what I got:
Input:
1234567890
Output:
49
50
Actually, 49 should be 1, and 50 should be 2.
You are getting ASCII value of characters 1 and 2. Use %c specifier to print the digits.
printf("%c\n",number[0]);
Warning! Your code may invoke undefined behaviour!
But we'll talk about it later. Let us address your actual question first.
Here is a step by step explanation of what is going on. The first thing you need to know is that every character literal in C is actually an integer for the compiler.
Try this code.
#include <stdio.h>
int main()
{
printf("%d\n", sizeof '1');
return 0;
}
The output is:
4
This shows that the character literal '1' is represented as 4 byte integer by the compiler. Now, let us see what this 4 byte integer for '1' is using the next code here.
#include <stdio.h>
int main()
{
int a = '1';
printf("a when intepreted as int : %d\n", a);
printf("a when intepreted as char: %c\n", a);
return 0;
}
Compile it and run it. You'll see this output.
a when intepreted as int : 49
a when intepreted as char: 1
What do we learn?
The character '1' is represented as the integer 49 on my system. This is so for your system too. That's because in my system as well as yours, the compiler is using ASCII codes for the integers where '1' is 49, '2' is 50, 'A' is 65, 'B' is 66, and so on. Note that the mapping of the characters to these codes could be different for another system. You should never rely on these integer codes to identify the characters.
So when I try to print this value as integer (using %d as the format specifier), well what gets printed is the integer value of '1' which is 49. However, if we print this value as a character (using %c as the format specifier), what gets printed is the character whose integer code is 49. In other words, 1 gets printed.
Now try this code.
#include <stdio.h>
int main()
{
char s[] = "ABC123";
int i;
printf("char %%d %%c\n");
printf("---- -- --\n");
for (i = 0; i < 6; i++) {
printf("s[%d] %d %c\n", i, s[i], s[i]);
}
return 0;
}
Now you should see this output.
char %d %c
---- -- --
s[0] 65 A
s[1] 66 B
s[2] 67 C
s[3] 49 1
s[4] 50 2
s[5] 51 3
Does it make sense now? You need to use the %c format specifier when you want to print the character. You should use %d only when you want to see the integer code that represents that character.
Finally, let us come back to your code. This is how you fix it.
#include <stdio.h>
int main()
{
char number[10];
scanf("%9[^\n]", number);
printf("%c\n", number[0]);
printf("%c\n", number[1]);
return 0;
}
There are two things to note.
I have used %c as the format specifier to print the character representation of the digits read.
I have altered the format specifier for scanf to accept at most 9 characters only where the characters are not newline characters. This is to make sure that a user cannot crash your program by inputting a string that is far longer than 9 characters. Why 9 instead of 10?. Because we need to leave one cell of the array empty for the null-terminator. A longer input would overwrite memory locations beyond the allocated 10 bytes for the number array. Such buffer overruns lead to code that invoke undefined behaviour which could either cause a crash or kill your cat.
printf("%c\n",number[0]); //print the 1st digit in the number
printf("%c\n",number[1]);
should do the job for you, what you see are ascii values.
your number array is an array of char, and so every element of it is a char.
when you type:
printf("%d\n",number[0]);
you printing the chars as integers, and so you get the ASCII code for each char.
change your statement to printf("%c\n",number[0]); to print chars as chars not as ints
Warning! Your code invokes undefined behaviour!
char number[10]; // Can only store 9 digits and nul character
scanf("%s",number); // Inputting 1234567890 (11 chars) will overflow the array!
Use fgets instead:
#define MAX_LEN 10
char number[MAX_LEN];
if(fgets(number, MAX_LEN, stdin)) {
// all went ok
}
Once you have fixed this, you can fix the printing problem. You are printing the character code (number), and not the actual character. Use different type specifier:
printf("%c\n",number[0]);

What are scanf("%*s") and scanf("%*d") format identifiers?

What is the practical use of the formats "%*" in scanf(). If this format exists, there has to be some purpose behind it. The following program gives weird output.
#include<stdio.h>
int main()
{
int i;
char str[1024];
printf("Enter text: ");
scanf("%*s", &str);
printf("%s\n", str);
printf("Enter interger: ");
scanf("%*d", &i);
printf("%d\n", i);
return 0;
}
Output:
manav#workstation:~$ gcc -Wall -pedantic d.c
d.c: In function ‘main’:
d.c:8: warning: too many arguments for format
d.c:12: warning: too many arguments for format
manav#manav-workstation:~$ ./a.out
Enter text: manav
D
Enter interger: 12345
372
manav#workstation:~$
For printf, the * allows you to specify the minimum field width through an extra parameter, e.g. printf("%*d", 4, 100); specifies a field width of 4. A field width of 4 means that if a number takes less than 4 characters to print, space characters are printed until the field width is filled. If the number takes up more space than the specified field width, the number is printed as-is with no truncation.
For scanf, the * indicates that the field is to be read but ignored, so that e.g. scanf("%*d %d", &i) for the input "12 34" will ignore 12 and read 34 into the integer i.
The star is a flag character, which says to ignore the text read by the specification.
To qoute from the glibc documentation:
An optional flag character `*', which says to ignore the text read for this specification. When scanf finds a conversion specification that uses this flag, it reads input as directed by the rest of the conversion specification, but it discards this input, does not use a pointer argument, and does not increment the count of successful assignments.
It is useful in situations when the specification string contains more than one element, eg.:
scanf("%d %*s %d", &i, &j) for the "12 test 34" - where i & j are integers and you wish to ignore the rest.
The * is used to skip an input without putting it in any variable. So scanf("%*d %d", &i); would read two integers and put the second one in i.
The value that was output in your code is just the value that was in the uninitialized i variable - the scanf call didn't change it.
See here
An optional starting asterisk indicates that the data is to be retrieved from stdin but ignored, i.e. it is not stored in the corresponding argument.
In scanf("%*d",&a) * skips the input. In order to read the inputs one has to use an extra "%d" in scanf. For example:
int a=1,b=2,c=3;
scanf("%d %*d %d",&a,&b,&c); //input is given as: 10 20 30
O/p:
a=10 b=30 and c=3; // 20 is skipped
If you use another %d i.e: scanf("%d %*d %d %d",&a,&b,&c); //input is given as: 10 20 30 40
then a=10 b=30 c=40.
If you use "," in scanf then no value will be taken after %*d i.e;
scanf("%d %*d,%d" &a,&b,&c)// 10 20 30
O/p:
a=10 b=2 c=3 will be the output.

Resources