Why do I get a segmentation fault with isdigit()? - c

Scenario 1:
Code:
int main(){
int a = 12345678;
if(isdigit(a)){
printf("ok: foo\n");
}
else{
printf("false: bar\n");
}
printf("test\n");
return EXIT_SUCCESS;
}
Output:
Segmentation fault
Scenario 2:
Code:
...
if(isdigit(a)){
//printf("ok: foo\n");
}
else{
//printf("false: bar\n");
}
printf("test\n");
...
Output:
test
and now the last, Code:
...
int a = 1234567;
...
Output:
ok: foo
test
What's wrong with isdigit()? I do not understand!

Probably because the compiler optimizes the isdigit function call from the code. That is it doesn't run it.
Also note that isdigit expects a character, not a number. http://www.cplusplus.com/reference/clibrary/cctype/isdigit/

This is because isdigit can be defined as macro like this
#define isdigit(c) ((map[c] & FLAG_DIGIT)==FLAG_DIGIT)
You call isdigit with integer value, but map array size is 256 elements. In this case you try to read value outside of array bounds -> segmentation fault. This segmentation fault can occurs randomly. Depending on your program or data size.

This was probably optimized by the compiler. As neither the if or the else does something, it was removed and the isdigit ends up not called. Be sure to
#include <ctype.h>
The segmentation fault is coming probably from the fact that you're passing a (not so small) number, when a character was expected. When you remove the printf statements and the compiler optimizes it, the call won't happen thus not failing.
Note that the headers can be in fact omitted since the program will be linked with the standard C library by default, so it works. But it's not a good idea, and you should see a warning at least.

First of all, isdigit(3) checks whether a character is a digit.
The segmentation fault probably (I'm positive) happens because you haven't included stdio.h.
Then you're calling printf which uses variable arguments without knowing its prototype (undefined behavior).

Related

Runtime error when using char as int to scanf and printf

int main()
{
char ch = 0;
int c = 0;
scanf("%d", &ch);
printf("%c", ch);
}
I can input the ASCII number and output the correct character. But the program crashes at the end of the code, the } sign.
Using Visual Studio 2019
Run-Time Check Failure #2 - Stack around the variable 'ch' was corrupted.
Since scanf has non-existent type safety, it can't know the type of parameters passed (one reason why the format string is there in the first place).
The stack corruption is caused by you lying to the compiler here: scanf("%d", &ch);. You tell it "trust me, ch is an int". But it isn't. So scanf tries to store 4 bytes in an area where only 1 byte is allocated and you get a crash.
Decent compilers can warn for incorrect format specifiers.
There are multiple problems in your code:
missing #include <stdio.h> ;
unused variable c ;
type mismatch passing a char variable address when scanf() expects an int * for the %d conversion specifier ;
missing test on scanf() return value ;
missing newline at the end of the output ;
missing return 0; (implied as of c99, but sloppy).
Here is a modified version:
#include <stdio.h>
int main() {
int ch;
if (scanf("%d", &ch) == 1) {
printf("%c\n", ch);
}
return 0;
}
I guess your question was not, "What did I do wrong?", or "Why didn't it work?".
I guess your question is, "Why did it work?", or, "Why did it print an error message after seeming to work correctly?"
There are lots of mistakes you can make which will corrupt the stack. This is one of them. Much of the time, these errors are rather inscrutable: If the memory corruption is severe enough that the memory management hardware can detect it, you may get a generic message like "Segmentation violation" at the instant the bad access occurs, but if not, if the damage isn't bad enough to cause any overt problems, your program may seem to work as you expected, despite the error.
It would be prohibitively expensive to perform explicit tests (in software) to check the stack for damage during every operation. Therefore, no attempt is made to do so, and the primary responsibility is placed on you, the programmer, not to do obviously wrong things like telling scanf to store an int in a char-sized box.
In this case, your system did make a check for stack damage, but as some kind of a one-time operation, only after the main function had returned. That's why the scanf and the printf seemed to work correctly, and the error message seemed to coincide with the closing } at the end of main.
Echoing an analogy I made in a comment, this is sort of like having a policeman write you a ticket for having done something dangerous that did not cause an accident. Why not write the ticket as you are doing the dangerous thing? Why write the ticket after the fact at all, since your dangerous behavior didn't cause an accident? Well, because sometimes that's just the way the world works.
I think you are trying to input an integer and print its char value so in my opinion this is what you are trying to do:
#include <iostream>
using namespace std;
int main()
{
int c = 0;
scanf("%d", &c);
printf("%c", c);
return 0;
}
Note: This is a C++ code but the syntax inside main function will work for C language as well

Calling isalpha Causing Segmentation Fault

I have the following program that causes a segmentation fault.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
printf("TEST");
for (int k=0; k<(strlen(argv[1])); k++)
{
if (!isalpha(argv[1])) {
printf("Enter only alphabets!");
return 1;
}
}
return 0;
}
I've figured out that it is this line that is causing the problem
if (!isalpha(argv[1])) {
and replacing argv[1] with argv[1][k] solves the problem.
However, I find it rather curious that the program results in a segmentation fault without even printing TEST. I also expect the isalpha function to incorrectly check if the lower byte of the char* pointer to argv[1], but this doesn't seem to be the case. I have code to check for the number of arguments but isn't shown here for brevity.
What's happening here?
In general it is rather pointless to discuss why undefined behaviour leads to this result or the other.
But maybe it doesn't harm to try to understand why something happens even if it is outside the spec.
There are implementation of isalpha which use a simple array to lookup all possible unsigned char values. In that case the value passed as parameter is used as index into the array.
While a real character is limited to 8 bits, an integer is not.
The function takes an int as parameter. This is to allow entering EOF as well which does not fit into unsigned char.
If you pass an address like 0x7239482342 into your function this is far beyond the end of the said array and when the CPU tries to read the entry with that index it falls off the rim of the world. ;)
Calling isalpha with such an address is the place where the compiler should raise some warning about converting a pointer to an integer. Which you probably ignore...
The library might contain code that checks for valid parameters but it might also just rely on the user not passing things that shall not be passed.
printf was not flushed
the implicit conversion from pointer to integer that ought to have generated at least compile-time diagnostics for constraint violation produced a number that was out of range for isalpha. isalpha being implemented as a look-up table means that your code accessed the table out of bounds, therefore undefined behaviour.
Why you didn't get diagnostics might be in one part because of how isalpha is implemented as a macro. On my computer with Glibc 2.27-3ubuntu1, isalpha is defined as
# define isalpha(c) __isctype((c), _ISalpha)
# define __isctype(c, type) \
((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) type)
the macro contains an unfortunate cast to int in it, which will silence your error!
One reason why I am posting this answer after so many others is that you didn't fix the code, it still suffers from undefined behaviour given extended characters and char being signed (which happens to be generally the case on x86-32 and x86-64).
The correct argument to give to isalpha is (unsigned char)argv[1][k]! C11 7.4:
In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined.
I find it rather curious that the program results in a segmentation fault without even printing TEST
printf doesn't print instantly, but it writes to a temporal buffer. End your string with \n if you want to flush it to actual output.
and replacing argv[1] with argv[1][k] solves the problem.
isalpha is intended to work with single characters.
First of all, a conforming compiler must give you a diagnostic message here. It is not allowed to implicitly convert from a pointer to the int parameter that isalpha expects. (It is a violation of the rules of simple assignment, 6.5.16.1.)
As for why "TEST" isn't printed, it could simply be because stdout isn't flushed. You could try adding fflush(stdout); after printf and see if this solves the issue. Alternatively add a line feed \n at the end of the string.
Otherwise, the compiler is free to re-order the execution of code as long as there are no side effects. That is, it is allowed to execute the whole loop before the printf("TEST");, as long as it prints TEST before it potentially prints "Enter only alphabets!". Such optimizations are probably not likely to happen here, but in other situations they can occur.

Ignoring return value of scanf

I have this issue where gcc using the Werror argument, comes up with the error 'ignoring return value of scanf'. Now, I checked the forums and I did do stuff such as putting it in an if statement which seemed to work fine, but the thing is, I do not get the error if I were to compile it at my University.
#include <stdio.h>
#include <stdlib.h>
#define EXAMPLE1 5
int main (int argc, char* argv[]) {
int example;
scanf ("%d", &example);
if (example <= EXAMPLE1) {
printf ("Woohoo\n");
} else {
printf ("Oohoow\n");
}
return EXIT_SUCCESS;
}
So this code for example would compile fine using gcc -Wall -Werror -O -o namehere namehere.c at my uni, but if I were to use it at home, the aforementioned error comes up. My uni is using gcc 4.9.2. I tried it at home on gcc 4.8.4, 4.8.5, 4.9.3.
Ignoring the return value of scanf() is not good because it means you are not checking for possible errors in input. Though some compilers or settings don't give warnings for that, you shouldn't ignore return values of scanf().
Try this:
#include <stdio.h>
#include <stdlib.h>
#define EXAMPLE1 5
int main (int argc, char* argv[]) {
int example;
if (scanf ("%d", &example) != 1) {
printf ("Read error\n");
}
else if (example <= EXAMPLE1) {
printf ("Woohoo\n");
} else {
printf ("Oohoow\n");
}
return 0;
}
You are not getting an error, the compiler is so friendly to give you a warning. And correctly! Upon erroneous input example will have a random value.
Always check that the return value of scanf matches the number of arguments you want to read.
scanf ("%d", &example);
This tells scanf to read a sequence of decimal digit characters (possibly with a prefixed negative sign) up to the first non-decimal character, and convert that sequence into an int value that gets stored into example.
What if the user enters something that is entirely non-decimal, or if stdin is closed? The scanf call would fail, indicating such a failure using a corresponding return value... but what would the value of example be in such a situation?
You need to check the return value to avoid using example when it contains garbage. If you try to use that variable, the behaviour of your program may be erratic. This might include segfaults.
Your compiler is within its rights to refuse to compile this code, because using an uninitialised (or otherwise indeterminate) variable is undefined behaviour.
In summary, it's well within your best interests to always check the return value because:
Some compilers might refuse to compile code that doesn't have such checks, as you've noticed.
Those that do compile your code will allow your program to behave erratically, using garbage when the user enters garbage or in some cases, possibly segfaulting due to use of a trap representation.

Infinite loop behaviour in C

I have the following code:
#include<stdio.h>
int main(){
int a = 1, b = 8;
while(a != b)
{
printf("asd");
fflush(stdout);
}
return 0;
}
Clearly, the program never stops. But why is "asd" not printed at all?
EDIT: This is the complete program. There are not any other lines. The first time I used Eclipse and MinGW and it didn't print anything. I tried then with gcc in linux and it was working as expected, even without fflush!
So probably this behaviour might be caused by the fact that some compilers optimize the code and modify the infinite loops.
fflush(stdin) is meaningless, and in fact causes undefined behaviour according to the standard - you probably meant fflush(stdout). If you make that change, you'll see output.

Why is printf not equivalent to scanf?

I have a program which displays "hi", but I do not understand why.
I understand both scanf and printf return the number of characters they read/write but how does it work in this case?
void main()
{
if(printf==scanf)
printf("hello");
else
printf("hi");
}
You aren't calling the functions and comparing the results, you are comparing the functions themselves, which boils down to comparing the addresses of the functions (function names will convert to function pointers in many contexts, this is one). What you wrote is equal to this:
/* this is the correct signature for main by the way, not `void main()` */
int main(int argc, char **argv) {
/* compare the address of printf to that of scanf */
if (&printf == &scanf) {
printf("hello");
} else {
printf("hi");
}
}
Since scanf and printf are not the same function they live at a different address so the comparison fails and hi is printed.
Here you compare the adreses of the functions and as the functions are not the same, the equality does not hold. I do not see what confuses you.
You are not calling printf or scanf in the if statement. Rather, you are comparing the location of scanf and printf function in the memory, which are different (otherwise, they will run the same code, and have the same functionality).
You only get back the return value if you invoke the function. An invocation will look like <function_name> ( <arguments separated by commas> ).
As others have already mentioned you are comparing the address of two functions (printf and scanf in this case) and since these functions cannot have the same address, the comparison fails making the program print "hi".
You can try the below code to understand it better
int main(void)
{
printf("printf = %x\n", printf);
printf("scanf = %x\n", scanf);
return 0;
}
Because the address of the function printf is not the same as the function scanf.
Just to add another angle on this matter. Others have already pointed out how you can compare the addresses to the functions. But this code make (well, it's a far stretch) sense:
int main()
{
if(printf("")==scanf(""))
printf("hello");
else
printf("hi");
}
This code is guaranteed to print "hello". Why? Well, lets first look at return values. printf will return the number of characters printed, which is zero for an empty string. scanf will return the number of successful assignments (not the number of characters read), which for an empty string is also zero. Well, if some error occurs, it can also return EOF, which I find highly unlikely even if I cannot guarantee that it will not happen. Well, printf can fail too, and will in that case return an unspecified negative number.
So, it will print "hello", unless both printf and scanf both encounters a problem, AND that printf returns EOF, in which it will print "hi" instead.
However, it could be the case that this is UB. I'm not sure if the order of evaluation is well defined, or even if that matters.

Resources