Getting access violation error while using %s in scanf_s - c

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.

Related

Unhandled exception at 0x00007FFB158DA726 (ucrtbase.dll) in AI.exe: 0xC0000005: Access violation writing location 0x00007FF76DE322E0

When I run the code here happen after
scanf("%[^\n]", order);
Full code:
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE
#include <stdio.h>
#include <Windows.h>
#include "Colors.h"
#include <string>
#include "Functions.h"
#include <stdbool.h>
using namespace std;
int main() {
//vars
char* order = "";
int WinH;
int WinW;
bool error = false;
GetDesktopResolution(WinH, WinW);
// end vars
//funcs
//DelayedStart();
//end funcs
Sleep(1500);
system("CLS");
Sleep(250);
SetConsoleTitle(L"AI APP - Main");
printf("Hello,\nHow can I help you\n>>");
F_GREEN;
scanf("%[^\n]", order); //error here
F_B_Defalt;
if (order == "open youtube") {
ShellExecute(0, 0, L"http://www.youtube.com", 0, 0, SW_SHOW);
}
else
{
printf("%s\n", order);
puts("Whoops");
}
system("PAUSE");
}
Visual Studio 2022 V17.4
You are scanning into a string literal(""), which provokes undefined behaviour!
Actually you should have gotten a compiler warning, because of assigning this string literal, which has type char const/*!!!*/ *, to a variable of char /*non-const!*/ *. Some compilers do allow this for reasons of compatibility to C. Some of these (e.g. GCC) allow to enhance this warning to a compilation error, not sure if MSVC does so, too, but if it does, you should do so!
Additionally this string literal only contains room for one single character, so (if it was possible at all...) you only could read an empty string into (containing the terminating null character), otherwise you'll provoke undefined behaviour again for writing beyond array bounds.
Either of these two kinds of undefined behaviour might have provoked the segmentation fault.
To fix provide a writable character buffer long enough to hold expected input:
char order[128];
// ...
scanf("%127[^\n]", order);
Note how in above format string a maximum length for reading characters is specified, this needs to be, though, one less than the buffer size as the scan operation will yet append the terminating null character.
Note, too, how order decays to a pointer to its first element implicitly, so you do not need to take the address of – actually this would even be wrong and provoke undefined behaviour for providing non-matching pointer types (char(*)[128] vs. char*) to the format specifier (even though the address would be the same).

How do I use tolower() with a char array?

I'm learning C in school and am doing some input and string comparisons and am running into what looks like a casting issue.
Here is my code:
size_t unit_match_index(char *userInput) {
char* unit = malloc(strlen(userInput) + 1);
strcpy(unit, userInput);
//convert to lowercase
for (size_t i = 0; i < strlen(unit); ++i) {
unit[i] = tolower(unit[i]);
/*C6385: invalid data from 'unit': the readable size is 'strlen(userInput)+1' bytes, but 2bytes may be read
C6386: buffer overrun while writing to 'unit': the writable size is [same as above]
*/
}
//...
}
After doing a little bit of research, it looks like tolower() looks for an int and returns an int (2 bytes), and thinks strlen(userInput)+1 may equate to 1, making the total unit array size only 1 byte.
Is there something I should be doing to avoid this, or is this just the analyzer being a computer (computers are dumb)? I'm concerned because I will lose marks on my assignment if there are errors.
As suggested in an answer to this related question, these two warnings are caused by a "bug" in the MSVC Code Analyser.
I even tried the 'fix' I suggested in my answer to that question (that is, using char* unit = malloc(max(strlen(userInput), 0) + 1);) – but it didn't work in your code (not sure why).
However, what did work (and I have no idea why) is to use the strdup function in place of your calls to malloc and strcpy – it does the same thing but in one fell swoop.
Adding the casts (correctly)1 suggested in the comments, here's a version of your code that doesn't generate the spurious C6385 and C6386 warnings:
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
size_t unit_match_index(char* userInput)
{
char* unit = strdup(userInput);
//convert to lowercase
for (size_t i = 0; i < strlen(unit); ++i) {
unit[i] = (char)tolower((unsigned char)unit[i]);
}
//...
return 0;
}
However, MSVC will now generate a different (but equally spurious) warning:
warning C4996: 'strdup': The POSIX name for this item is deprecated.
Instead, use the ISO C and C++ conformant name: _strdup. See online
help for details.
As it happens, the strdup function (without the leading underscore) is adopted as part of the ISO Standard since C23 (6/2019).
1 On the reasons for the casts when using the tolower function, see: Do I need to cast to unsigned char before calling toupper(), tolower(), et al.?. However, simply adding those casts does not silence the two code analysis warnings.

Implicit declaration of function 'scan_s' [-Wimplicit-function-declaration]

I've been looking at other questions and none of the solutions have worked so I'll ask my own question.
I'm working on a linux VM and having trouble compiling my code, here are my includes, the error received by the compiler and the code its referring to:
Error:
linux.c:156:11: warning: implicit declaration of function 'scan_s' [-Wimplicit-function-declaration]
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "ctype.h"
scanf_s("%[^\n]s", filename, maxFilename);
scanf_s is part of the bounds-checking extension that your compiler may not support. Use #ifdef __STDC_LIB_EXT1__ to see if your library/implementation supports it -- if not, fall back to using something like
char fmt[16];
sprintf(fmt, "%%%d[^\n]", maxFilename);
scanf(fmt, maxFilename, filename);
or
fgets(filename, maxFilename, stdin);
if (char *p = strchr(filename, '\n')) *p = '\0';
instead.
Note that the s in the format string of your example is non-sensical and will not match anything (any s will be absorbed by the %[^\n] as it is not a newline.
As far as I know, only Microsoft compilers support this extension.

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.

Linux <-> Windows Storing an address of string

I have a serious problem with writing an App on Linux.
I have this code
#include <stdio.h>
int main()
{
char ar[10][10];
strcpy(ar[1], "asd");
strcpy(ar[2], "fgh");
int test[2];
test[1] = (int)ar[1];
printf("%s %x | %s %x\n\n", ar[1], ar[1], test[1], test[1]);
return 0;
}
And it works on Windows well, but when i want to run this on Linux i got
Segmentation Fault or Unauthorized Access to memory.
Your program invokes undefined behavior. It assumes that a pointer will fit into an int, which isn't required. Usually pointers will fit on Unix boxes and fail on Windows; but you should use an appropriate integer type, such as intptr_t from stdint.h if you need to do such conversions. Note that strictly speaking the integer must be cast back to a pointer type before being passed to printf.
Using a pointer type to printf and a large enough integral type results in correct behavior: http://ideone.com/HLExMb
#include <stdio.h>
#include <stdint.h>
int main(void)
{
char ar[10][10];
strcpy(ar[1], "asd");
strcpy(ar[2], "fgh");
intptr_t test[2];
test[1] = (intptr_t)ar[1];
printf("%s %x | %s %x\n\n", ar[1], ar[1], (char*)test[1], (char*)test[1]);
return 0;
}
Note though that casting pointers into integral types is generally frowned upon and is likely to result in program bugs. Don't go there unless you absolutely need to do so for one reason or another. When you're starting out in C it is unlikely that you'll ever need to do this.

Resources