Is there any way to handle error index out of bounds in C
i just want to to know, please explain it in context of this example.
if i enter a string more than 20 char i get * stack smashing detected *: ./upper1 terminated
Aborted (core dumped)
main()
{
char st[20];
int i;
/* accept a string */
printf("Enter a string : ");
gets(st);
/* display it in upper case */
for ( i = 0 ; st[i] != '\0'; i++)
if ( st[i] >= 'a' && st[i] <= 'z' )
putchar( st[i] - 32);
else
putchar( st[i]);
}
I want to handle those and stop them and display a custom message as done in Java's Exception Handling. Is it possible ? If yes how
Thanks in advance
To answer the original question: there is no way to handle implicitly out-of-bound array indexes in C. You should add that check explicitly in your code or you should prove (or at least be absolutely sure) that it does not happen. Beware of buffer overflow and other undefined behavior, it can hurt a lot.
Remember that C arrays don't "know" their size at runtime. You should know and manage that size, especially when passing arrays (which become decayed into pointers). Read also about flexible array members in struct-s (like here).
BTW, your code is poor taste. First, the char st[20]; is really too small these days: an input line can have really a hundred of characters (I often have terminal emulators wider than 80 columns). So make it e.g.
char st[128];
Then, as every one told you, gets(3) is dangerous, it is documented as "Never use this function". Take the habit of reading the documentation of every function that you dare use.
I would suggest to always clear such a string buffer with
memset (st, 0, sizeof st);
You should at the very least use fgets(3), but read the documentation first. You'll need to handle the failure case.
Also, your conversion to upper-case is specific to ASCII (and some other encodings). It won't work on old EBCDIC machine. And it is unreadable. So use isalpha(3) to detect letters (in ASCII or other single-byte encoding); but in UTF-8 it is more complex, since some letters -eg cyrillic ones- are encoded on several bytes). My family name (СТАРЫНКЕВИЧ when spelt in Russian) contains an Ы -which is a single letter called yery - whose UTF-8 encoding for the capital letter is 0xD0 0xAB on two bytes. You'll need an UTF-8 library like unistring to handle these. And use toupper(3) to convert (e.g. ASCII) letters to upper-case.
Notice that your main function is wrongly defined. It should return an int and preferably be declared as int main(int argc, char**argv).
At last, on Posix systems, the "right" way to read a line is to use the getline(3) function. It can read a line as wide as permitted by system resources (so it might read a line of a million characters on my machine). See this answer.
Regarding exceptions, C don't really have these (so most programmers take the habit to have functions giving some error code). However, for non-local jumps consider setjmp(3) to be used with great caution. (In C++, you have exceptions and they are related to destructors).
Don't forget to compile with all warnings and debug info (e.g. with gcc -Wall -g if using GCC). You absolutely need to learn how to use the debugger (e.g. gdb) and you also should use a memory leak detector like valgrind.
Yes, you must use fgets() instead of gets(). In fact, gets() is officially deprecated and should never, ever be used, because it is impossible to use safely as you discovered.
Though its not directly possible to detect that the user has written out of bounds it, we can add some logic to make sure to throw an error without crashing.
int main (int argc, char **argv)
{
char user_input [USERINPUT_MAX];
for (int i = 0; i < USERINPUT_MAX; ++i)
{
// read the character
// check for enter key, if enter break out of loop after adding null at end
// if not enter,store it in array
}
if (i == USERINPUT_MAX)
{
printf ("you have exceeded the character range");
}
}
I guess you get the idea of how to handle such situations from user input.
Related
It seems like there is problem in scanf_s
Here is my code.
#include <stdio.h>
#include "stack.h"
int main(){
int disk;
int hanoi[3][9];
char input[3] = { 0,0,0 };
int moveDisk;
for (int i = 0; i < 9; i++) {
hanoi[0][i] = i + 1;
hanoi[1][i] = 0;
hanoi[2][i] = 0;
}
printf("Insert the number of disks(1~9): ");
scanf_s("%d", &disk);
while (input[0] != 'q') {
printf("%3c %3c %3c\n", 'A', 'B', 'C');
for (int i = 0; i < disk; i++) {
printf("%3d %3d %3d\n", hanoi[0][i], hanoi[1][i], hanoi[2][i]);
}
scanf_s("%s", &input); //getting moving disk -- LOCATION OF ERROR
}
}
I have no idea how to solve this
No doubt you tried to use scanf() in the normal way and Visual Studio reported an error instructing you to use scanf_s()? It is not a direct replacement. For all %c, %s and %[ format specifiers you must provide two arguments - the target receiving the input, and the size of target (or strictly the number of elements).
In VS2019 even at /W1 warning level, it issues a clear explanation of the problem in this case:
warning C4473: 'scanf_s' : not enough arguments passed for format string
message : placeholders and their parameters expect 2 variadic arguments, but 1 were provided
message : the missing variadic argument 2 is required by format string '%s'
message : this argument is used as a buffer size
Don't ignore the warnings, and certainly don't disable them globally (/W0).
So in this case:
scanf_s("%s", input, sizeof(input) ) ;
again more strictly:
scanf_s("%s", input, sizeof(input)/sizeof(*input) ) ;
but the latter is really only necessary for wscanf_s (wide characters). In both cases you could use the _countof() macro, but it is Microsoft specific.
scanf_s("%s", input, _countof(input) ) ;
Note also the lack of an & before input. You don't need it for an argument that is already array or pointer. That is true of scanf() too.
Whilst there are arguments for using scanf_s() over scanf() (which is intrinsically more dangerous), it can just make life difficult if you are learning from standard examples or using a different toolchain. The simpler solution is just to disable the warning, and understand that it is unsafe:
You cited the line
scanf_s("%s", &input);
There are several things wrong with this line:
You are reading a string into a character array. This is an exception to the normal pattern for scanf, in that you do not need the &.
You are using the semistandard scanf_s, instead of the normal scanf. scanf_s is supposed to be "safer", but in order for it to provide its safetiness guarantees you have to call it differently than normal scanf, too. You have to tell it the size of the array you're reading the string into. Combined with #1 above, I believe a more correct call would be scanf_s("%s", input, 3);.
For most purposes, a string of size 3 would be far too small for reading a line of input from the user. Since in this case I guess you're only reading a "line" to give yourself an opportunity to hit RETURN before the program makes another trip through its loop, I guess it's okay.
As I mentioned, scanf_s is not quite Standard, so using it is a mixed bag. Pros: 1. It's allegedly safer. 2. Some people (including perhaps your instructor) will recommend always using it for that reason. Cons: 3. It's nut fully standard (it's an optional part of the standard) meaning that not all C compilers and libraries will support it. 4. Its calling patterns are necessarily quite different than normal scanf; it is not a drop-in replacement, so confusion is likely. (I'm not saying "don't use scanf_s", but you should be aware of its somewhat dubious status.)
If you want to read a line of input from the user before continuing, and if the line might be a "q" or something else, scanf (of any variety) might not be the best choice. In particular, %s wants to read a non-whitespace string, so if you just hit the Return key, it's going to keep waiting. This might or might not be a problem for you. (Or it might not be something you need to worry about right now; you may have bigger fish to fry.)
How can I solve this problem during debugging?
Run your program step by step using the debugger. Then when you get the exception, you've found the line causing it.
Restart your program and go up to the line where the exception will occur. That is stop on that line without execution it.
Then with the debugger, you can look at all variables and try to understand if their value is what you expect.
Does this answered your question?
BTW: The compiler should at least emitted some warnings. You really should first fix those warnings. If you have no warning, make sure you have turned on all warnings in the compiler options.
I am absolutely new to C programming. Currently I am preparing for my new course of studies IT Security. In a slightly older exam I found a task where I have no approach how to solve it. The task is in German. In principle it is about finding critical errors.
It is not written how the passed parameters look like.
1) I have come to the point that you should not use strcpy because it has no bounds checking.
2) Also char[10] should not be used if you want to store 10 characters (\0). It should be char[11].
Is it possible to read Adresses or write sth due the printf(argv[1]) command ?
I would like to mention again that you help me here personally and do not help to collect bonus points in the university.
#include <stdio.h>
int main(int argc, char *argv[])
{
char code[10];
if(argc != 2) return 1;
printf(argv[1]);
strcpy(code, "9999999999");
for(int i = 0; i < 10; ++i){
code[i] -= argv[1][i] % 10;
}
printf(", %s\n", code);
return 0;
}
See
related.
you should not use strcpy() because it has no bounds checking
Nothing in C has bounds checking unless either
the compiler writer put it there, or
you put it there.
Few compiler writers incorporate bounds checking into their products, because it usually causes the resulting code to be bigger and slower. Some tools exist (e.g.
Valgrind,
Electric Fence)
to provide bounds-checking-related debugging assistance, but they are not commonly incorporated into delivered software because of limitations they impose.
You absolutely should use strcpy() if
you know your source is a NUL-terminated array of characters, a.k.a. "a string", and
you know your destination is large enough to hold all of the source array including the terminating NUL
because the compiler writer is permitted to use behind-the-scenes tricks unavailable to compiler users to ensure strcpy() has the best possible performance while still providing the behaviour guaranteed by the standard.
char[10] should not be used if you want to store 10 characters (\0)
Correct.
To store 10 characters and the terminating NUL ('\0'), you must have at least 11 characters of space available.
Is it possible to read Adresses or write sth due the printf(argv[1]) command ?
In principle: maybe.
The first argument to printf() is a format string which is interpreted by printf() to determine what further arguments have been provided. If the format string contains any format specifications (e.g. "%d" or "%n") then printf() will try to retrieve corresponding arguments.
If they were not in fact passed to it, then it invokes Undefined Behaviour which is Bad.
An attacker could run your program giving it a command-line argument containing format specifiers, which would lead to such UB.
The right way to print an arbitrary string like this with printf() is printf("%s", argv[1]);
I want to understand a number of things about the strings on C:
I could not understand why you can not change the string in a normal assignment. (But only through the functions of string.h), for example: I can't do d="aa" (d is a pointer of char or a array of char).
Can someone explain to me what's going on behind the scenes - the compiler gives to run such thing and you receive segmentation fault error.
Something else, I run a program in C that contains the following lines:
char c='a',*pc=&c;
printf("Enter a string:");
scanf("%s",pc);
printf("your first char is: %c",c);
printf("your string is: %s",pc);
If I put more than 2 letters (on scanf) I get segmentation fault error, why is this happening?
If I put two letters, the first letter printed right! And the string is printed with a lot of profits (incorrect)
If I put a letter, the letter is printed right! And the string is printed with a lot of profits and at the end something weird (a square with four numbers containing zeros and ones)
Can anyone explain what is happening behind?
Please note: I do not want the program to work, I did not ask the question to get suggestions for another program, I just want to understand what happens behind the scenes in these situations.
Strings almost do not exist in C (except as C string literals like "abc" in some C source file).
In fact, strings are mostly a convention: a C string is an array of char whose last element is the zero char '\0'.
So declaring
const char s[] = "abc";
is exactly the same as
const char s[] = {'a','b','c','\0'};
in particular, sizeof(s) is 4 (3+1) in both cases (and so is sizeof("abc")).
The standard C library contains a lot of functions (such as strlen(3) or strncpy(3)...) which obey and/or presuppose the convention that strings are zero-terminated arrays of char-s.
Better code would be:
char buf[16]="a",*pc= buf;
printf("Enter a string:"); fflush(NULL);
scanf("%15s",pc);
printf("your first char is: %c",buf[0]);
printf("your string is: %s",pc);
Some comments: be afraid of buffer overflow. When reading a string, always give a bound to the read string, or else use a function like getline(3) which dynamically allocates the string in the heap. Beware of memory leaks (use a tool like valgrind ...)
When computing a string, be also aware of the maximum size. See snprintf(3) (avoid sprintf).
Often, you adopt the convention that a string is returned and dynamically allocated in the heap. You may want to use strdup(3) or asprintf(3) if your system provides it. But you should adopt the convention that the calling function (or something else, but well defined in your head) is free(3)-ing the string.
Your program can be semantically wrong and by bad luck happening to sometimes work. Read carefully about undefined behavior. Avoid it absolutely (your points 1,2,3 are probable UB). Sadly, an UB may happen to sometimes "work".
To explain some actual undefined behavior, you have to take into account your particular implementation: the compiler, the flags -notably optimization flags- passed to the compiler, the operating system, the kernel, the processor, the phase of the moon, etc etc... Undefined behavior is often non reproducible (e.g. because of ASLR etc...), read about heisenbugs. To explain the behavior of points 1,2,3 you need to dive into implementation details; look into the assembler code (gcc -S -fverbose-asm) produced by the compiler.
I suggest you to compile your code with all warnings and debugging info (e.g. using gcc -Wall -g with GCC ...), to improve the code till you got no warning, and to learn how to use the debugger (e.g. gdb) to run your code step by step.
If I put more than 2 letters (on scanf) I get segmentation fault error, why is this happening?
Because memory is allocated for only one byte.
See char c and assigned with "a". Which is equal to 'a' and '\0' is written in one byte memory location.
If scanf() uses this memory for reading more than one byte, then this is simply undefined behavior.
char c="a"; is a wrong declaration in c language since even a single character is enclosed within a pair of double quotes("") will treated as string in C because it is treated as "a\0" since all strings ends with a '\0' null character.
char c="a"; is wrong where as char c='c'; is correct.
Also note that the memory allocated for char is only 1byte, so it can hold only one character, memory allocation details for datatypes are described bellow
I am originally a Java programmer who is now struggling with C and specifically C's pointers.
The idea on my mind is to receive a string, from the user, on a command line, into a character pointer. I then want to access its individual elements. The idea is later to devise a function that will reverse the elements' order. (I want to work with anagrams in texts.)
My code is
#include <stdio.h>
char *string;
int main(void)
{
printf("Enter a string: ");
scanf("%s\n",string);
putchar(*string);
int i;
for (i=0; i<3;i++)
{
string--;
}
putchar(*string);
}
(Sorry, Code marking doesn't work).
What I am trying to do is to have a first shot at accessing individual elements. If the string is "Santillana" and the pointer is set at the very beginning (after scanf()), the content *string ought to be an S. If unbeknownst to me the pointer should happen to be set at the '\0' after scanf(), backing up a few steps (string-- repeated) ought to produce something in the way of a character with *string. Both these putchar()'s, though, produce a Segmentation fault.
I am doing something fundamentally wrong and something fundamental has escaped me. I would be eternally grateful for any advice about my shortcomings, most of all of any tips of books/resources where these particular problems are illuminated. Two thick C books and the reference manual have proved useless as far as this.
You haven't allocated space for the string. You'll need something like:
char string[1024];
You also should not be decrementing the variable string. If it is an array, you can't do that.
You could simply do:
putchar(string[i]);
Or you can use a pointer (to the proposed array):
char *str = string;
for (i = 0; i < 3; i++)
str++;
putchar(*str);
But you could shorten that loop to:
str += 3;
or simply write:
putchar(*(str+3));
Etc.
You should check that scanf() is successful. You should limit the size of the input string to avoid buffer (stack) overflows:
if (scanf("%1023s", string) != 1)
...something went wrong — probably EOF without any data...
Note that %s skips leading white space, and then reads characters up to the next white space (a simple definition of 'word'). Adding the newline to the format string makes little difference. You could consider "%1023[^\n]\n" instead; that looks for up to 1023 non-newlines followed by a newline.
You should start off avoiding global variables. Sometimes, they're necessary, but not in this example.
On a side note, using scanf(3) is bad practice. You may want to look into fgets(3) or similar functions that avoid common pitfalls that are associated with scanf(3).
Thank you everybody so far for your input and advice!
Additionally:
After testing and toying further, it seems individual calls to FileReader succeed. But calling FileReader multiple times (these might be separate versions of FileReader) causes the issue to occur.
End Add
Hello,
I have a very unusual problem [please read this fully: it's important] (Code::Blocks compiler, Windows Vista Home) [no replicable code] with the C File Reading functions (fread, fgetc). Now, normally, the File Reading functions load up the data correctly to a self-allocating and self-deallocating string (and it's not the string's issue), but this is where it gets bizarre (and where Quantum Physics fits in):
An error catching statement reports that EOF occurred too early (IE inside the comments section at the start of the text file it's loading). Printing out the string [after it's loaded] reports that indeed, it's too short (24 chars) (but it has enough space to fit it [~400] and no allocation issues). The fgetc loop iterator reports it's terminating at just 24 (the file is roughly 300 chars long) with an EOF: This is where it goes whacky:
Temporarily checking Read->_base reports the entire (~300) chars are loaded - no EOF at 24. Perplexed, [given it's an fgetc loop] I added a printf to display each char [as a %d so I could spot the -1 EOF] at every step so I could see what it was doing, and modified it so it was a single char. It loops fine, reaching the ~300 mark instead of 24 - but freezes up randomly moments later. BUT, when I removed printf, it terminated at 24 again and got caught by the error-catching statement.
Summary:
So, basically: I have a bug that is affected by the 'Observer Effect' out of quantum physics: When I try to observe the chars I get from fgetc via printf, the problem (early EOF termination at 24) disappears, but when I stop viewing it, the error-catch statement reports early termination.
The more bizarre thing is, this isn't the first time it's occurred. Fread had a similar problem, and I was unable to figure out why, and replaced it with the fgetc loop.
[Code can't really be supplied as the code base is 5 headers in size].
Snippet:
int X = 0;
int C = 0;
int I = 0;
while(Copy.Array[X] != EOF)
{
//Copy.Array[X] = fgetc(Read);
C = fgetc(Read);
Copy.Array[X] = C;
printf("%d %c\n",C,C); //Remove/add this as necessary
if(C == EOF){break;}
X++;
}
Side-Note: Breaking it down into the simplest format does not reproduce the error.
This is the oldest error in the book, kind of.
You can't use a variable of type char to read characters (!), since the EOF constant doesn't fit.
You need:
int C;
Also, the while condition looks scary, you are incrementing X in the loop, then checking the (new) position, is that properly initialized? You don't show how Copy.Array is set up before starting the loop.
I would suggest removing that altogether, it's very strange code.
In fact, I don't understand why you loop reading single characters at all, why not just use fread() to read as much as you need?
Firstly, unwind's answer is a valid point although I'm not sure whether it explains the issues you are seeing.
Secondly,
printf("%d %c\n",C,C); //Remove/add this as necessary
might be a problem. The %d and %c format specifiers expect an int to be the parameter, you are only passing a char. Depending on your compiler, this might mean that they are too small.
This is what I think the problem is:
How are you allocating Copy.Array? Are you making sure all its elements are zeroed before you start? If you malloc it (malloc just leaves whatever garbage was in the memory it returns) and an element just happens to contain 0xFF, your loop will exit prematurely because your while condition tests Copy.Array[X] before you have placed a character in that location.
This is one of the few cases where I allow myself to put an assignment in a condition because the pattern
int c;
while ((c = fgetc(fileStream)) != EOF)
{
doSomethingWithC(c);
}
is really common
Edit
Just read your "Additionally" comment. I think it is highly likely you are overrunning your output buffer. I think you should change your code to something like:
int X = 0; int C = 0; int I = 0;
while(X < arraySize && (C = fgetc(Read)) != EOF)
{
Copy.Array[X] = C;
printf("%d %c\n", (int)C, (int)C);
X++;
}
printf("\n");
Note that I am assuming that you have a variable called arraySize that is set to the number of characters you can write to the array without overrunning it. Note also, I am not writing the EOF to your array.
You probably have some heap corruption going on. Without seeing code it's impossible to say.
Not sure if this is your error but this code:
C = fgetc(Read);
Copy.Array[X] = C;
if(C == EOF){break;}
Means you are adding the EOF value into your array - I'm pretty sure you don't want to do that, especially as your array is presumably char and EOF is int, so you'll actually end up with some other value in there (which could mess up later loops etc).
Instead I suggest you change the order so C is only put in the array once you know it is not EOF:
C = fgetc(Read);
if(C == EOF){break;}
Copy.Array[X] = C;
Whilst this isn't what I'd call a 'complete' answer (as the bug remains), this does solve the 'observer effect' element: I found, for some reason, printf was somehow 'fixing' the code, and using std::cout seemed to (well, I can't say 'fix' the problem) prevent the observer effect happening. That is to say, use std::cout instead of printf (as printf is the origin of the observer effect).
It seems to me that printf does something in memory on a lower level that seems to partially correct what does indeed seem to be a memory allocation error.