if statement in C - c

Going through some entry level C programming and having trouble with this seemingly very simple logical operator. The first if statement is skipped if you enter last name Paul. Also trying to understand buffer size when using scanf_s.
int main(){
char name[25];
printf("what is your last name? ");
printf("(Please capitalize the first letter!)\n");
scanf_s(" %s", name, 2);
if ((name[0] >= 'P') && (name[0] <= 'S'))
{
printf("You must go to room 232 for your tickets\n ");
}
else
{
printf("You can get your tickets in the lobby\n");
}
return 0;
}

In your scanf_s(" %s", name, 2); statement, the third argument here specifies the size of the character array (name) into which to read the given response. I'm not sure why you have given 2 as that size, when you have declared, in the char name[25]; line, that you have an actual size of 25.
However, with that 2 value, the read will fail if you type in more than one character (try just giving "P" as input, and you will enter the if block).
From the documentation for scanf_s (bolding mine):
The buffer size includes the terminal null. You can use a width
specification field to ensure the token that's read in fits into the
buffer. When a token is too large to fit, nothing is written to the
buffer unless there's a width specification.
Also, it is always a good idea to check the return value from scanf_s (and related functions), to make sure the read was successful! Adding a few check as shown in the snippet below will show you what's going on, with various different inputs:
//...
int n = scanf_s(" %s", name, 2);
printf("Items read = %d; Name given is: %s ...\n", n, name);
//...
With this, when I enter "Paul" as input, I see the following:
what is your last name? (Please capitalize the first letter!)
Paul
Items read = 0; Name given is: ...
You can get your tickets in the lobby
Note: On the debate about whether or not to use scanf_s in place of scanf (as the Microsoft compiler advises), see here: Difference between scanf and scanf_s.

Related

C printf function data formats

Very simple C printing question!
#include <stdio.h>
#include <conio.h>
int main() {
int Age = 0;
printf("Enter your Age\n");
scanf("%d",&Age);
char Name;
printf("Enter your Full name\n");
scanf("%s",&Name);
printf("My name is %s and I am aged %d" ,&Name,Age);
return 0;
}
When I input "blah" and 1, for some reason this returns:
"My name is Blah and I am aged 1929323232"
I presume I am misunderstanding a data format in either the scanf or the printf functions but can't work it out.
The problem is because of line
char Name;
Name is of type char. That means that it is supposed to store only one character. As a result
1. The scanf() is not able to store the input text properly (this will result in a crash in most cases or other undefined behaviour depending on the system - which judging by the output you provided is what you got)
2. (if the code didn't crash) Treating Name as a string with the %s argument in printf() essentially outputs garbage.
The type that corresponds to strings in C is char * (or char[]). Essentially, changing Name to some statically allocated char-array while performing the necessary changes in the next lines should fix your error:
char Name[256]; //allocated 256 bytes in Name array
printf("Enter your Full name\n");
scanf("%s",Name); // removed & before Name
printf("My name is %s and I am aged %d" ,Name,Age); // same here
You could also opt to go with a dynamically allocated string of type char * but I guess that's a different topic altogether.
As a general suggestion, I think you should look at pointers more closely. Especially in C, almost all string operations involve being aware of pointer mechanisms.

String input using C scanf_s

I've been trying to look for answer myself, but I can't find one.
I want to insert a part of the programming that reads in a string like "Hello" and stores and can display it when I want, so that printf("%s", blah); produces Hello.
Here's the code part that's giving me trouble
char name[64];
scanf_s("%s", name);
printf("Your name is %s", name);
I know that printf isn't the problem; the program crashes after something is input after a prompt. Please help?
From the specification of fscanf_s() in Annex K.3.5.3.2 of the ISO/IEC 9899:2011 standard:
The fscanf_s function is equivalent to fscanf except that the c, s, and [ conversion
specifiers apply to a pair of arguments (unless assignment suppression is indicated by a
*). The first of these arguments is the same as for fscanf. That argument is
immediately followed in the argument list by the second argument, which has type
rsize_t and gives the number of elements in the array pointed to by the first argument
of the pair. If the first argument points to a scalar object, it is considered to be an array of
one element.
and:
The scanf_s function is equivalent to fscanf_s with the argument stdin
interposed before the arguments to scanf_s.
MSDN says similar things (scanf_s() and fscanf_s()).
Your code doesn't provide the length argument, so some other number is used. It isn't determinate what value it finds, so you get eccentric behaviour from the code. You need something more like this, where the newline helps ensure that the output is actually seen.
char name[64];
if (scanf_s("%s", name, sizeof(name)) == 1)
printf("Your name is %s\n", name);
I used this very often in my university classes so this should work fine in Visual Studio (tested in VS2013):
char name[64]; // the null-terminated string to be read
scanf_s("%63s", name, 64);
// 63 = the max number of symbols EXCLUDING '\0'
// 64 = the size of the string; you can also use _countof(name) instead of that number
// calling scanf_s() that way will read up to 63 symbols (even if you write more) from the console and it will automatically set name[63] = '\0'
// if the number of the actually read symbols is < 63 then '\0' will be stored in the next free position in the string
// Please note that unlike gets(), scanf() stops reading when it reaches ' ' (interval, spacebar key) not just newline terminator (the enter key)
// Also consider calling "fflush(stdin);" before the (eventual) next scanf()
Ref: https://msdn.microsoft.com/en-us/library/w40768et.aspx
The scanf_s function is equivalent to scanf except that %c, %s, and %[ conversion specifiers each expect two arguments (the usual pointer and a value of type rsize_t indicating the size of the receiving array, which may be 1 when reading with a %c into a single char)
Your code doesn't provide the size of receiving array, also the variable name is a pointer pointing to the first character of the array, so it contains the address of name[0]. Therefore your first argument name in scanf_s is correct because name is a pointer, also note that, for the second argument you can't insert the size of a pointer like sizeof(name) because it is always same. You need to specify the size of your char array (name[64]), so for the second argument you should insert sizeof(name[64]) or 64*sizeof(char).
You can correct your code as follows:
char name[64];
if (scanf_s("%s", name, sizeof(name[64])) == 1)
printf("Your name is %s\n", name);
Here is a part of code that works for me fine:
char name[64];
scanf_s("%63s", name,(unsigned)_countof(name));
printf("Your name is %s", name);
For more information here is a link:
https://learn.microsoft.com/de-de/cpp/c-runtime-library/reference/scanf-s-scanf-s-l-wscanf-s-wscanf-s-l?view=msvc-170
Best Regards
#include<stdio.h>
int main()
{
char name[64];
printf("Enter your name: ");
scanf("%s", name);
printf("Your name is %s\n", name);
return 0;
}
#include<stdio.h>
int main()
{
char name[64];
printf("Enter your name: ");
gets(name);
printf("Your name is %s\n", name);
return 0;
}
you should do this : scanf ("%63s", name);
Update:
The below code worked for me:
#include <stdio.h>
int main(void) {
char name[64];
scanf ("%63s", name);
printf("Your name is %s", name);
return 0;
}
if you are using visual studio,
go to Project properties -> Configuration Properties -> C/C++-> Preprocessor -> Preprocessor Definitions click on edit and add _CRT_SECURE_NO_WARNINGS click ok, apply the settings and run again.
Note: this is only good if you are doing your homework or something like that and it's not recommended for production.

Whats wrong with my SIMPLE C program?

I am writing a super simple command line based program in C. It's just a small test and the code is very simple. So what it is meant to do is to ask the user for their name, maths grade, english grade, computing grade. Then it figures out their average grade and also tells them the name they entered. Yes I know this is an extremely simple program, but I'm still doing something wrong.
The problem is, one part of my code will run first telling the user to enter their name and then once they do this and press enter the rest of my code will run all at once and then stop working. It's weird I just don't understand what is wrong.
#include <stdio.h>
int main(int argc, const char * argv[])
{
char chr;
char firstname;
int mathsmark, englishmark, computingmark, averagemark;
printf("What is your name?\n");
scanf("%c", &firstname);
printf("\n");
printf("What is your maths mark?\n");
scanf("%d", &mathsmark);
printf("\n");
printf("What is your english mark?\n");
scanf("%d", &englishmark);
printf("\n");
printf("What is your computing mark?\n");
scanf("%d", &computingmark);
printf("\n");
printf("Your name is: %c", firstname);
printf("\n");
averagemark = (mathsmark + englishmark + computingmark) / 3;
printf("%d", averagemark);
printf("\n");
chr = '\0';
while (chr != '\n') {
chr = getchar ();
}
return 0;
}
One major problem is that you've declared firstname to be a single character long, and when you try to read the name from the console, you're using the %c conversion specifier, which reads the next single character from the input stream and stores it to firstname. The remainder of the name is left in the input stream to foul up the remaining scanf calls.
For example, if you type "Jacob" as a first name, then the first scanf call assigns J to firstname, leaving "acob\n" in the input stream.
The next scanf call attempts to convert "acob\n" to an integer value and save it to mathsmark, which fails ("acob\n" is not a valid integer string). Same thing happens for the next two scanf calls.
The last loop
while (chr != '\n')
{
chr = getchar();
}
finally consumes the rest of "acob\n", which contains the newline character (because you hit Enter after typing the name), causing the loop and program to exit.
How do you fix this?
First, you need to declare firstname as an array of char:
char firstname[SOME_SIZE] = {0};
where SOME_SIZE is large enough to handle all your cases. The you need to change scanf call to
scanf("%s", firstname);
This tells scanf to read characters from the input stream up to the next whitespace character and store the results to the firstname array. Note that you don't need to use the & operator here; under most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type, and the value of the expression will be the address of the first element in the array.
Note that scanf is not very safe, and it's not very robust. If you enter more characters than your buffer is sized to hold, scanf will happily store those extra characters to memory following the array, potentially clobbering something important. You can guard against this by using an explicit field width in the conversion specifier, like
scanf(*%29s", firstname);
but in general it's a pain.
scanf is also not very good at detecting bad input. If you enter "12er" as one of your marks, scanf will convert and assign the "12", leaving the "er" in the stream to foul up the next read.
scanf returns the number of successful assignments, so one way to guard against bad input is to check the return value, like so:
if (scanf("%d", &mathmarks) != 1)
{
printf("Bad input detected for math marks\n");
}
Unfortunately, scanf won't remove bad characters from the stream; you'll have to do that yourself using getchar or similar.
This is a common mistake amongst newer C/C++ developers. The scanf function detects you hitting the ENTER/RETURN key to signal the end of input, but it also catches the \n character as well at the end of the input string, so you essentially get two RETURNS being detected.
Please read up on an example of using fgets and sscanf here:
http://www.linuxforums.org/forum/programming-scripting/67560-problem-scanf.html
It will resolve this issue very quickly for you. In the meantime, I strongly urge you to check out this book:
http://www.amazon.com/Primer-Plus-5th-Stephen-Prata/dp/0672326965
It is the most commonly used C programming book in high school and colleges in North America, and has TONS of examples for you to work through, including this specific program you demonstrated above. The print version has more examples than the e-book, so I would just cough up the $30.00 for the printed version.
Good luck!
You might want to look at a few tutorials. Maybe one on Format specifiers and one on strings in C
scanf() reads data from stdin and stores them as specified by the format specifiers. In this case:
char firstname;
scanf("%c", &firstname);
Read 1 character from stdin and store it to firstname:
>> What is your first name?
Mike
Now firstname == 'M' because scanf() read 1 character as we requested.
What you wanted to do was read a string (a bunch of characters):
char firstname[5]; // an array of characters
scanf("%s", firstname); // store as a string
firstname[4] = '\0'; // Truncate the result with a NULL to insure no overflow
>> What is your first name?
Mike
Now firstname is [M][i][k][e][\0] because scanf() read 1 string, as we requested.
Note the same holds true for printf(), a printf with a %c will give you one character where as a printf() with a %s will give you all the characters until the NULL terminator.
You have (at least) two choices.
char firstname[number_big_enough_to_hold_long_name];
/*or */
char *firstname = malloc(sizeof(char) * number_big_enough_to_hold_long_name);
/* ... code ... */
free(firstname);
Further it would be best to limit width of read. scanf() does not know the size (available space) of firstname.
scanf("%number_big_enough_to_hold_long_names", ...
/* i.e. */
char firstname[32];
if(scanf("%31s", firstname) == EOF) {
perror("bad");
return 1;
}
Further you should check if there is anything left before trying next read. I.e. If someone enters "My Name" then only "My" will end up in firstname and "Name" will be left in input stream.
And getchar() returns an int not a char.
getchar
scanf
And search "ansi c char arrays tutorial" or similar.

Am I using scanf incorrectly?

Each line of input is a line with a command followed by numbers (except in the exit case).
I cannot figure out what I am doing wrong. This segment is looking for the store command and then does the action store entails:
char command[20];
while(strcmp(command, "exit") != 0)
{
/*scans for command strings inputted*/
scanf(" %s", command);
/* handles store command*/
if(strcmp(command, "store") == 0)
{
memory[0] = 1;
scanf("%d %d %d %d %d", &startx, &starty, &finishx, &finishy, &number);
for( i = startx; i < finishx; i++)
{
for(j = starty; j < finishy; j++)
{
square[i][j] = number;
}
}
}
}
Yes, you are using it wrongly(a). The line:
scanf(" %s", command);
has no bounds checking on the input. If someone enters more than 19 characters into your program, it will overflow the char command[20] and result in undefined behaviour.
The two major problems with scanf are:
using it with an unbounded %s since there's no way to control how much data is entered. My favourite saying is that scanf is to scan formatted information and there's not much less formatted than user input.
not checking how many items were scanned - it's possible to scan less than you expected.
If you want to do it right, see here. It uses fgets to get a line, protecting from buffer overflows and detecting problems.
Once you have the line as a string, you can safely sscanf it to your heart's content, since you know the upper bound on the length and you can always return to the start of the string to re-scan (not something easy to do with an input stream).
Other problems with your code include:
The initial strcmp on an uninitialised buffer. It could actually be (arbitrarily) set to exit which would cause your loop not too start. More likely is that it's not a valid C string at all, meaning strcmp will run off the end of the buffer. That won't necessarily end well.
No checking that all your numeric items were entered correctly. You do that by checking the return value from scanf (or sscanf should you follow my advice on using the rock-solid input function linked to here) - it should be five but entering 1 hello 2 3 4 would result in a return code of one (and all but startx unchanged).
No range checking on input. Since square has limited dimensions, you should check the inputs to ensure you don't write outside of the array. That's both numbers that are too large and negative numbers.
(a) Syntactically, what you have is correct. However, from a actual semantic point of view (i.e., what you mean to happen vs. what may happen), there's a hole in your code large enough to fly an Airbus A380 through :-)

Is there a way to read a c-string and then an int with a single scanf in C?

Hey,
I'm trying to get this function to get the following output with the listed input, the "..." is where I'm not sure what to write:
void Question8(void)
{
char sentence[100];
int grade;
scanf(….);
printf("%s %d", sentence, grade);
}
Input:
My CS Grade is 1000
Output:
My CS Grade is 100
However, the kicker is that I need the scanf to read a c-string and then an int with a single scanf command, is this even possible?
Edit:
I can only edit the code in the location with the three periods ( "..." ), I cannot use anything more. I can assume that the input listed is expected but I cannot change anything outside of the three periods.
The output does not contain typos, the purpose of this assignment is to use flags and escape sequences.
It is possible to read pre-formatted string using scanf, however the format must be strict.
This version will continue to read the input until a digit is encountered and then read an integer.
Here is your code again:
char sentence[100];
int grade;
scanf("%[^0-9] %d",sentence,&grade);
printf("%s %d\n", sentence, grade);
I'll get this over with quick:
<obligatory_rant>
stupid question, but I guess it's homework and you're
stuck with these absurd limitations
</obligatory_rant>
Then, if you need to read everything up to but excluding the first digit, then the number:
if (scanf("%100[^0-9] %3d", text, &number) == 2)
...
Notes:
100 in "%100[... should be whatever your actual buffer size is to protect against buffer overrun.
The %3d documents that at most 3 digits should partake the the numeric value, so 1000 is correctly read as 100.
[^...] means the string made up of characters not ("^") in the following set, which is then specified as 0-9 - the digits.
if (... == 2) tests whether both positional parameters were scanned / converted successfully.
If you can't add an if and error message, then simply:
scanf("%100[^0-9] %3d", text, &number)
Tested in Visual Studio 2008
#include <stdio.h>
int main()
{
char sentence[100];
int grade = 0;
scanf("%[^0-9] %d",sentence,&grade);
printf("%s %d", sentence, grade);
return 1;
}
Input :
My CS Grade is 100
Output :
My CS Grade is 100
This is a really horrible question. A correct set of scanf parameters would be "%14c%3d", sentence, &grade
Because a space is included in the printf statement the trailing space needs to not be stored in sentence. Because the input contains other spaces there is no other solution (that I can thing of) than a fixed length. The integer parsing also requires a fixed length to truncate 1000 to 100.
I can think of no reason to ever write code anything like this. The code fits the requirements but wouldn't be useful in any other circumstances. I think that this is a very poor training exercise.

Resources