Why doesn't Visual Studio's scanf_s() function take string inputs? - c

I use Visual Studio 2022, which marks scanf() function as unsafe and deprecates it. It recommends me to use scanf_s() instead.
So yesterday my teacher was teaching us strings in C and showed us a program to receive a string from the keyboard which I tried out in my compiler
Using scanf_s() to input a string returned error C4473 or C6064 even though my code was identical to that of my teacher's aside from the scanf() difference.
#include<stdio.h>
#include<stdlib.h>
void main() {
char name[25];
printf("Enter your name ");
scanf_s("%s", name);//gave an ERROR
printf("Hello %s!", name);
}
I tried using the regular scanf() along with disable warning and it worked.
#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable : 4996)
void main() {
char name[25];
printf("Enter your name ");
scanf("%s", name);//worked as intended
printf("Hello %s!", name);
}
Why does scanf_s fail take string inputs?

From the C Standard *K.3.5.3.2 The fscanf_s function) This description is the same as for the function scanf_s
4 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.
So you need to write
scanf_s( "%s", name, sizeof( name ) );
Also this call of scanf
scanf("%s", name);
will be safer if to rewrite it like
scanf( "%24s", name );
Pay attention to that according to the C Standard the function main without parameters shall be declared like
int main( void )

Related

Getting access violation error while using %s in scanf_s

I am a beginner and I am learning C and using Visual Studio Code 2019 and I get an error like this:
Exception thrown at 0x7C97E63C (ucrtbased.dll) in string.exe: 0xC0000005: Access violation writing location 0x00900000".
Here is my code:
#include <stdio.h>
int main() {
char str[50];
scanf_s("%s", &str);
printf("%s", str);
return 0;
}
I know it is a very noob type question but when I compile the same code with Code::Blocks, it runs fine but ultimately I have to use VScode to build projects so I am stuck here. How can I fix this problem?
Your code has undefined behavior because you do not pass the size argument scanf_s expects after the destination pointer for the %s conversion. Furthermore, you should pass str, not &str although that should not cause a problem. You should also test if scanf_s succeeds to avoid calling printf with an uninitialized array if it fails, for example if the input stream is an empty file.
Finally, there is a problem with scanf_s that is well beyond your current skill level: this function is defined with different semantics on Windows and in the C Standard, so the way you can pass the size argument depends on the compiler.
For standard complying compilers, such as gcc and clang in linux and Mac/OS, you would use sizeof str which has type size_t, but on Windows you must cast this as (unsigned) because Microsoft's version of scanf_s expects this type, which has a different size on 64-bit systems. For this and other reasons, scanf_s should not be used in a portable program.
Here is a modified version for linux and Mac/OS:
#include <stdio.h>
int main() {
char str[50];
if (scanf("%49s", str) == 1) {
printf("%s\n", str);
}
return 0;
}
Here is a modified version for Windows, where the compiler insists on the use of scanf_s with non-standard semantics:
#include <stdio.h>
int main() {
char str[50];
if (scanf_s("%49s", str, (unsigned)sizeof(str)) == 1) {
printf("%s\n", str);
}
return 0;
}
The 49 in %49s prevents scanf_s from triggering an implementation defined exception.

Behavior of printf() and scanf()| How to know that way built-in function work?

The prototype of printf and scanf in stdio.h are:
int scanf ( const char * format, ... );
int printf ( const char * format, ... );
Seems like it accepts the same type of argument, that is const char * format. I understand that is a pointer to a constant char variable that has name "format". So both function accept format name as first variable. But the list of argument after ,... make me confused.
Take 2 example, we will see printf accept something like content of variable
Example:
int a = 20;
int *pa = &a;
printf("%d", a);
printf ("%d", *pa);
scanf() accepts the address of variable:
Example:
int a =20;
int *pa = &a;
scanf("%d", &a);
scanf("%d", pa);
In short, it easy to accept that is the way these function work, but how I can find where they define, prototype in header file is not enough, I can try to google something like:"built a printf() for yourself", some books like "C programming language" also teach how to create some built-in function.
But I think there must have some file that saved all these functions.
In short:
The printf function takes a set of values to print.
The scanf function takes a set of pointers to variables where to store the value it has read.
Some related things you might want to research includes variable argument functions (the whole ... argument thing), and how to emulate pass by reference in C.
The const char* format argument is the first argument of the function -- the format string, which is "%d" in your examples.
The other arguments (a or pa in your examples) are varargs, denoted by the ... in the argument list of the function declaration. This allows a function to take a variable number of arguments.
This means that printf can take more arguments, like so:
int a = 1;
int b = 2;
printf("a=%d b=%d\n", a, b);
This would print a=1 b=2.
The type of the first argument in both functions scanf() and printf() are the same, i.e. a string. The ellipsis (...) represents a variable length list of arguments and is referred to as varargs. The types of the varargs parameters are not the same. Hence both scanf() and printf() may take more than one argument.
scanf() will store the entered value into memory and hence requires a pointer, i.e. an address in memory so it knows where to store the entered value.
printf() displays a value that is already stored in a memory area.
So basically you could say that scanf() writes to a memory area whereas printf() reads from a memory area.

How does the compiler know the prototype of printf( ) in this code?

In the following code,
#include<conio.h>
clrscr();
gotoxy(10, 20);
ch= getch(a);
we can see that the library functions have been called without defining their prototype, the three library functions: clrscr() gotoxy(int int) and getch() have their prototypes defined in the conio.h header file which appear in the header file itself like this,
void clrscr();
void gotoxy(int int);
int getch();
But in the following code how does the compiler know the prototype of the printf() function? Since the code gets executed without any errors, although in the first printf() the last int format specifier prints the garbage value and in the second the value of j doesn't get printed at all since it has not been specified.
#include<stdio.h>
int i=10, int j=20;
printf("%d%d%d",i,j);
printf("%d",i,j);
How does the header file stdio.h describe the scenarios when the format specifiers are float or char variables for the printf() functions?
The compiler knows the prototype because it's declared in <stdio.h>, which you're including.
<stdio.h> does not describe the format specifiers. It simply says
int printf(const char *, ...);
The ... indicates that printf takes a variable number of arguments (of unknown type).
Your first call to printf has undefined behavior (not enough arguments for the format string). Your second call is fine (excess arguments are simply ignored). C compilers are not required to detect format string issues like this.
The stdio header always includes the same declaration of printf() which is:
int printf(const char *fmt, ...);
the declaration is always the same no matter which placehoder you put into your format string.
Normally the definition\implementation of printf iterates over each character in the fmt string and will replace each identified placeholder with the appropriate argument. The compiled code will try to use the arguments instead of the placeholders in the same order as they are specified in the source code.
Any predefined function like printf should be prototyped or declared before using, in respective header file so that while executing the program compiler can verify whether programmer uses correct format or not.
printf() function prototype is declared in header file called stdio.h.
when compiler executes first line of your code which is #include<stdio.h> It came to know about printf prototype.
man 3 printf says
int printf(const char *format, ...);// last 3 dots specifies the variable no of arguments printf can take
In your code below printf is causing undefined behaviour because printf expects 3 arguments but you provided only 2 arguments.
printf("%d%d%d",i,j);

Compiler error variable declaration

I am getting a strange error that's saying that my variables are not declared even though I have declared them in main. Am I missing something?
Error 4 error C2065: 'destination' : undeclared identifier c:\users\owner\documents\visual studio 2012\projects\project36\project36\source.c 26 1 Project36
I am programming in C.
variable declaration:
char sourcePiece;
char destination;
function call:
askForMove(sourcePiece, destination);
function def:
void askForMove(char sourcePiece, char destination) {
char sourcePiece;
char destination;
printf("\nEnter your desired move. First enter the starting position, followed by the ending position in letters: ");
scanf(" %c %c", &sourcePiece, &destination);
}
prototype:
void askForMove(char, char );
As it has been noted by some commenters, one of the problems is that you cannot have a local variable and a formal parameter with the same name. I suggest that you remove the declarations of the local variables, because it's the parameters that you want to use in your function, not them.
The full version of the code and the latest screenshot with the errors that you posted indicate that the compiler complains about the local variable declarations made in main function. The compiler complains because the variable declarations are interleaved with statements inside main, which was not supported by "classic" C language (C89/90). In order to compile this code you need a C99 (or later) compiler.
The code is easy to fix for a pre-C99 compiler - just move all local variable declarations to the beginning of the enclosing block (i.e. to the beginning of main in your case).
You Should Know that
Formal parameters, are treated as local variables within a function.
So Here You are duplicating them and it is causing error.
void askForMove(char sourcePiece, char destination) {
char sourcePiece; //Redeclaring already present in formal parameter.
char destination; //Redeclaring already present in formal parameter.
printf("\nEnter your desired move. First enter the starting position, followed by the ending position in letters: ");
scanf(" %c %c", &sourcePiece, &destination);
}
Remove Them
void askForMove(char sourcePiece, char destination) {
printf("\nEnter your desired move. First enter the starting position, followed by the ending position in letters: ");
scanf(" %c %c", &sourcePiece, &destination);
}
Also Note your question is not a good example of how one should write , Always Post Minimal, Complete, and Verifiable example.
Update
What AnT is saying make sense , see this C89, Mixing Variable Declarations and Code
I'm not sure what you intended to achieve in your program but you have a duplication in your variable names. Don't use the same name for the function argument and the local variable.

C Programming : Codeblocks stops working with C till I make a tiny change. Any idea why?

The code is included below:
When I run the program with the line printf(ch) it says project could not be executed. However when I use the placeholder, the project works just fine. Any idea why it is such?
#include <stdio.h>
#include <stdlib.h>
int main()
{
char arr[10];
printf("Enter a password. \n");
scanf("%s",arr );
// printf(arr);
char ch;
int i;
for (i=0; i<10; i++)
{
ch=arr[i];
printf(ch);
//printf("%c",ch);--> if i use this instead of printf(ch) it works fine. Can this please be explained
}
}
That is because printf expects the argument should be in the const char*, ... as input argument while
char ch;
is not of pointer type
So you "can" do:
char ch = 'A';
printf(&ch); //this is bad because not only it is not well-formatted but also, though compiled, may cause undefined behavior. This is to only show you the idea
but cannot do:
char ch = 'A';
printf(ch);
Edited (after paddy's correction):
The correct way to print it using printf is by using the print format provided for character,
char ch = 'A';
printf("%c", ch);
Hope it can help.
What do you expect when you lie to the compiler? :-)
The printf function's prototype, declared in <stdio.h> is
int printf(const char *format, ...);
which means the first argument must be given and it must be of type pointer-to-char.
If instead you pass printf a char then that is mis-interpreted as a pointer-to-char, causing undefined behavior in C lingo.
Speak the truth to the compiler and it will cooperate. Finding out about the truth starts with reading the documentation of the library functions you use and enabling all warnings your compiler offers. This particular one is easily caught by almost all modern compilers.
PS: using proper terminology also helps communicating problems. What you call placeholder is called argument or, more specifically, format.

Resources