I'm working on a program which I need to get string from a user and do some manipulates on it.
The problem is when my program ends I am getting "Access violation writing location 0x00000000." error message.
This is my code
}
//code
char *s;
s=gets();
//code
}
After some reading I relized that using gets() may cause some problems so I changed char *s to s[20] just to check it out and it worked fine without any errors at the end of the program.
The thing is that I don't know the string size in advance, thus, I'm not allowed (academic ex) to create string line as -> s[HugeNumber] like s[1000].
So I have no other choice but using gets() function.
Any way to solve my problem?
Thanks in advance
PS
Also tried using malloc as
char *temp;
char *s;
temp = gets();
s= (char*)malloc((strlen(temp) +1)* sizeof(char));
Error still popup at the end.
As long as I have *something = gets(); my program will throw an error at the end.
It looks like you are expecting gets to allocate an appropriately-sized string and return a pointer to it but that is not how it works. gets needs to receive the buffer as a parameter so you would still need to declare the array with a huge number. In fact, I am surprised that you managed to get your code to compile since you are passing the wrong number of arguments to gets.
char s[1000];
if (gets(s) == NULL) {
// handle error
}
The return value of gets is the same pointer that you passed as a parameter to it. The only use of the return value is to check for errors, since gets will return NULL if it reached the end of file before reading any characters.
A function that works more similarly to what you want is getline in the GNU libc:
char *s;
size_t n=0;
getline(&s, &n, stdin);
printf("%s", s); // Use the string here
free(s); //Then free it when done.
Alternatively, you could do something similar using malloc and realloc inside a loop. Malloc a small buffer to start out then use fgets to read into that buffer. If the whole line fits inside the buffer you are done. If it didn't then you realloc the buffer to something larger (multiply its size by a constant factor each time) and continue reading from where you stopped.
Another approach is to give up on reading arbitrarily large lines. The simplest thing you can do in C is to set up a maximum limit for line length (say, 255 characters), use fgets to read up to that number of characters and then abort with an error if you are given a line that is longer than that. This way you stick to functions in the standard library and you keep your logic as simple as possible.
You have not allocated temp.
And 3 kinds of C you should avoid i.e.
void main() use int main() instead
fflush(stdin)
gets() use fgets() instead
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Can someone help me with this issue? For some reason, no matter what I try, doing printf isn't printing in my code. I've been trying to use the flush method, but that seems to just cause other issues. Is there anything else I can do?
int main(void) {
char **line;
size_t bufsize=MAXBUF;
printf("Type your name: ");
getline(&line,&bufsize,stdin);
}
You are trying to pass in an empty pointer, this pointer isn't pointing to any meaningful address at the start of the program. So the problem with this is that even if you were successful, it would overwrite some random address in memory with the input, and this is almost certainly what you don't want as it will cause a segmentation fault or a crash.
However that's not the reason why it's not compiling. It's not compiling because you are trying to pass in char *** to a function that expects char **.
So what I would do is:
#include <stdio.h>
int main(void) {
char *line=NULL;
size_t bufsize=0;
printf("Type your name: ");
if(getline(&line,&bufsize,stdin)==-1){
puts("Error: User cancelled input.");
}
else{
printf("Entered: %s",line);
}
free(line);
return 0;
}
So what this code does is that it creates a pointer to an array of characters but it sets the pointer to point to NULL so that the program can see it's not pointing anywhere, and then its address (&line) is given to the getline function, this turns the char * type into a char ** which is required by the getline function. Whenever you put a & in front of something in C, it adds an extra * to the type.
You probably know this already, but if a function states that it returns something, you should always return something, even if it's nonsense otherwise depending on the type that should be returned, that can sometimes cause a crash.
There was nothing wrong with your use of printf, that was fine. printf doesn't necessarily fflush to stdout, often the \n character will trigger a flush, but it's implementation specific, so if your program crashes before an fflush is written to stdout, then you may never see the last printf. You can try an fflush(stdout); before the getline function, but after the getline function may not work because it may crash before then.
In your case what's happening is that before the printf writes to the screen the getline takes in the address of the pointer (or pointer to a pointer), dereferences it to a pointer, isn't able to, so before you have a chance to enter in any keystrokes it crashes, losing the stdout pipe, so you end up never seeing your prompt.
When i run the altered code, above, i get:
XXXX#dell:~$ gcc Deleteme.c
XXXX#dell:~$ ./a.out
Type your name: test1
Entered: test1
XXXX#dell:~$
And it runs correctly under Linux. The key lesson in all this is that, terminals are slow to update on the screen, so some time in the past, the decision was made to separate out the functionality of printf.
There are two components to printf:
The part that writes the text to stdout.
The part that updates the terminal with stdout (the flush).
This question is interesting because 1) succeeded, but the system crashed before 2) was completed.
The documentation for getline says the first parameter must be a char **, but you pass it the address of line. Since line is a char **, &line is a char ***, which is the wrong type.
getline() allocates and re-allocates memory. The address of the length and the buffer need to reflect that.
int main(void) {
char *line = NULL;
size_t bufsize = 0;
printf("Type your name: ");
fflush(stdout); // Flush output before reading.
ssize_t len = getline(&line, &bufsize, stdin);
if (len < 0) Handle_error_with_code();
...
free(line); // When done, free memory
}
There is no need to allocate any memory before calling getline().
getline() expects line, bufsize to reflect allocated data via malloc() and friends. It is easy enough to start with NULL, 0 here.
First you are passing the address of line to the getline(), the documentation says that the first argument is the address of the first character position where the input string will be stored. It’s not the base address of the buffer, but of the first character in the buffer.
This pointer type (a pointer-pointer or the ** thing) causes massive confusion.
second your line pointer does not point to anything this should fix it:
char *line = (char *)malloc(bufsize * sizeof(char));
now line is pointing to valid memory address which we requested via malloc() function.
Good evening everybody, I am learning C++ on Dev C++ 5.9.2, I am really novice at it. I intentionnally make my programs crash to get a better understanding of bugs. I've just learned that we can pass a char string to a function by initializing a pointer with the address of the array and that was the only way to do it. Therefore we should always pass to the function the size of that string to handle it properly. It also means that any procedure can run with a wrong size passed in the argument line hence I supposed we could read farther than the allocated memory assigned to the string.
But how far can we do it? I've tested several integers and apparently it works fine below 300 bytes but it doesn't for above 1000 (the program displays characters but end up to crash). So my questions are :
How far can we read or write on the string out of its memory range?
Is it called an overflow?
How does the program detect that the procedure is doing something unlegit?
Is it, the console or the code behind 'cout', that conditions the shutting down of the program?
What is the condition for the program to stop?
Does the limit depend on the console or the OS?
I hope my questions don't sound too trivial. Thank you for any answer. Good day.
#include <iostream>
using namespace std;
void change(char str[])
{
str[0] = 'C';
}
void display(char str[], int lim)
{
for(int i = 0; i < lim; i++) cout << str[i];
}
int main ()
{
char mystr[] = "Hello.";
change(mystr);
display(mystr, 300);
system("PAUSE");
return 0;
}
The behavior when you read past the end of an array is undefined. The compiler is free to implement the read operation in whatever way works correctly when you don't read beyond the end of the buffer, and then if you do read too far - well, whatever happens is what happens.
So there are no definite answers to most of your questions. The program could crash as soon as you read 1 byte too far, or you could get random data as you read several megabytes and never crash. If you crash, it could be for any number of reasons - though it likely will have something to do with how memory is managed by the OS.
As an aside, the normal way to let a function know where a string ends is to end it with a null character rather than passing a separate length value.
Hi Im new to coding in C and I can't seem to find the problem which causes a segfault after the while loop starts.
int main() {
char option;
char nickname;
printf("Welcome to our chat program. Please select mode (Send,Nickname,Exit): ");
while (gets(option)) {
if(!strncmp(option, "Exit", 4)) {
break;
}
if(!strncmp(option, "Nickname", 8)){
set_nickname(nickname);
}
if(!strncmp(option, "Send", 4)){
if(!nickname){
nickname = "Anonymous";
printf("Your nickname was set to Anonymous!");
}
send_message(nickname);
}
}
There are many issues with the code. Let's discuss them one by one.
First of all, a char is not sufficient to hold a string, you need either
an array
a pointer with proper (dynamic) memory allocation.
Using the first approach, you need to change
char option;
char nickname;
to
#define SIZ 64
char option[SIZ] = {0};
char nicknamep[SIZ] = {0};
Then, instead of using gets(), you should be using fgets() to avoid the possibility of buffer overflow. Something like
fgets(option, SIZ, stdin);
will do.
That said, once option becomes an array, you cannot assign to it. You need to use strcpy() to copy the content into the array. For example,
strcpy(nickname, "Anonymous");
There is no memory allocated for the strings.
You need someting like this:
char option[50];
char nickname[50];
and use strcpy() here:
nickname = "Anonymous";
and check the string with strlen() for example.
if(!nickname){
It is also safer to use fgets() with a length parameter to prevent buffer overflow.
while (gets(option)) {
option needs to be char[???]
Not sure about nickname but it also needs memory allocated and/or initialisation. How do you set it? What value do you use?
You'll also need to check for strlen(nickname)>0 rather than !nickname which will test for a null pointer, not an empty string.
Never ever use gets; it cannot be used correctly. Instead, use fgets, with stdin as the third parameter.
You will notice that fgets takes the length of the storage you want to assign as its second parameter. The lack of this parameter in the gets function is why it cannot be used correctly. You should pass it the value 1 in your case, and pass it the address of your char variable. fgets will then read one character into your variable.
If you want to read more, you need to start by allocating more storage for the data you'll read. For instance, you could allocate space for 80 characters:
char string[80];
You can now use fgets with string as the first character, 80 as the second, and stdin as the third. fgets will then read up to 80 characters from stdin.
If you don't want to store that number in two locations in your source code, you can use the sizeof operator instead, or use a macro to predefine the size of your buffer.
I got these test code and just curious, why passing pointer to gets() results in a runtime error?
void main()
{
char *value="gogo";
puts(value);
value="11";
puts(value);
gets(value);
}
Because char *value="gogo"; is more likely than not allocated to READ ONLY MEMORY!
Better:
#include <stdio.h>
#include <string.h>
#define MAX_LINE 80
int main()
{
char value[MAX_LINE] ="gogo";
puts(value);
strcpy (value, "11");
puts(value);
fgets(value, MAX_LINE, stdin);
puts(value);
return 0;
}
Here is a good link with more details: Storage for Strings in C
PS:
gets() is Evil. Avoid it if at all possible: Why gets() is bad
The pointer value points to (the static array associated with) a string literal.
Attempting to modify a string literal has undefined behavior. In this case, your compiler stores the string "gogo" in memory marked as read-only by the operating system, and attempting to modify it causes your program to crash.
If you declare a pointer to a string literal, you should define it as const:
const char *value = "gogo";
so the compiler will diagnose any attempt to modify it. Or, if you really want to modify the string, define it as an array:
char value[] = "gogo";
which the means that you can't assign a value to value, but you can use strcpy to update it.
Some more problems:
void main() is wrong [*]; the correct definition is int main(void). If you're using a book that told you to use void main(), please get a better one; its author does not know C very well.
Never use the gets function; it is inherently unsafe, and has been removed from the language. (It cannot guard against input longer than the array into which the value is stored.) You can use fgets instead; it's a bit more complicated to use, but it can be used safely.
You need to add
#include <stdio.h>
to the top of your source file to make these functions visible. If your compiler didn't complain about calls to undeclared functions, find out how to increase its warning level.
[*] Saying that void main() is wrong slightly overstates the case. A conforming compiler may permit it, and no compiler is required to complain about it, but there is no good reason to take advantage of that. int main(void) is always correct. Any C book or tutorial that advocates using void main() was almost certainly written by someone who does not know C well enough to be writing books or tutorials about it.
Here, your pointer points to a string literal ("gogo"). String literals are not guaranteed to be writable. You need to allocate your own memory:
char value[50] = "gogo";
...
gets(value);
However, this is not safe, as gets does not take the size of the buffer, and thus might overflow your buffer. (Which could also lead to a runtime error). NEVER use gets, as the manpage states:
BUGS
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.
Much better to allocate your own memory:
char user_input[200];
fgets(user_input, 200, stdin);
You might need to check user_input, to see if it ends with a newline. If it does, then fgets read a whole line. If it doesn't, then the the user typed more than ~200 characters into the line, and you'll need to read more to get the whole line. I've used 200 here. Choose a size that makes sense for your data. You can also use malloc to allocate memory on-the-fly, and put fgets into a loop in order to read an entire line into a buffer.
This may be a very basic question for some. I was trying to understand how strcpy works actually behind the scenes. for example, in this code
#include <stdio.h>
#include <string.h>
int main ()
{
char s[6] = "Hello";
char a[20] = "world isnsadsdas";
strcpy(s,a);
printf("%s\n",s);
printf("%d\n", sizeof(s));
return 0;
}
As I am declaring s to be a static array with size less than that of source. I thought it wont print the whole word, but it did print world isnsadsdas .. So, I thought that this strcpy function might be allocating new size if destination is less than the source. But now, when I check sizeof(s), it is still 6, but it is printing out more than that. Hows that working actually?
You've just caused undefined behaviour, so anything can happen. In your case, you're getting lucky and it's not crashing, but you shouldn't rely on that happening. Here's a simplified strcpy implementation (but it's not too far off from many real ones):
char *strcpy(char *d, const char *s)
{
char *saved = d;
while (*s)
{
*d++ = *s++;
}
*d = 0;
return saved;
}
sizeof is just returning you the size of your array from compile time. If you use strlen, I think you'll see what you expect. But as I mentioned above, relying on undefined behaviour is a bad idea.
http://natashenka.ca/wp-content/uploads/2014/01/strcpy8x11.png
strcpy is considered dangerous for reasons like the one you are demonstrating. The two buffers you created are local variables stored in the stack frame of the function. Here is roughly what the stack frame looks like:
http://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Call_stack_layout.svg/342px-Call_stack_layout.svg.png
FYI things are put on top of the stack meaning it grows backwards through memory (This does not mean the variables in memory are read backwards, just that newer ones are put 'behind' older ones). So that means if you write far enough into the locals section of your function's stack frame, you will write forward over every other stack variable after the variable you are copying to and break into other sections, and eventually overwrite the return pointer. The result is that if you are clever, you have full control of where the function returns. You could make it do anything really, but it isn't YOU that is the concern.
As you seem to know by making your first buffer 6 chars long for a 5 character string, C strings end in a null byte \x00. The strcpy function copies bytes until the source byte is 0, but it does not check that the destination is that long, which is why it can copy over the boundary of the array. This is also why your print is reading the buffer past its size, it reads till \x00. Interestingly, the strcpy may have written into the data of s depending on the order the compiler gave it in the stack, so a fun exercise could be to also print a and see if you get something like 'snsadsdas', but I can't be sure what it would look like even if it is polluting s because there are sometimes bytes in between the stack entries for various reasons).
If this buffer holds say, a password to check in code with a hashing function, and you copy it to a buffer in the stack from wherever you get it (a network packet if a server, or a text box, etc) you very well may copy more data from the source than the destination buffer can hold and give return control of your program to whatever user was able to send a packet to you or try a password. They just have to type the right number of characters, and then the correct characters that represent an address to somewhere in ram to jump to.
You can use strcpy if you check the bounds and maybe trim the source string, but it is considered bad practice. There are more modern functions that take a max length like http://www.cplusplus.com/reference/cstring/strncpy/
Oh and lastly, this is all called a buffer overflow. Some compilers add a nice little blob of bytes randomly chosen by the OS before and after every stack entry. After every copy the OS checks these bytes against its copy and terminates the program if they differ. This solves a lot of security problems, but it is still possible to copy bytes far enough into the stack to overwrite the pointer to the function to handle what happens when those bytes have been changed thus letting you do the same thing. It just becomes a lot harder to do right.
In C there is no bounds checking of arrays, its a trade off in order to have better performance at the risk of shooting yourself in the foot.
strcpy() doesn't care whether the target buffer is big enough so copying too many bytes will cause undefined behavior.
that is one of the reasons that a new version of strcpy were introduced where you can specify the target buffer size strcpy_s()
Note that sizeof(s) is determined at run time. Use strlen() to find the number of characters s occupied. When you perform strcpy() source string will be replaced by destination string so your output wont be "Helloworld isnsadsdas"
#include <stdio.h>
#include <string.h>
main ()
{
char s[6] = "Hello";
char a[20] = "world isnsadsdas";
strcpy(s,a);
printf("%s\n",s);
printf("%d\n", strlen(s));
}
You are relying on undefined behaviour in as much as that the compiler has chose to place the two arrays where your code happens to work. This may not work in future.
As to the sizeof operator, this is figured out at compile time.
Once you use adequate array sizes you need to use strlen to fetch the length of the strings.
The best way to understand how strcpy works behind the scene is...reading its source code!
You can read the source for GLibC : http://fossies.org/dox/glibc-2.17/strcpy_8c_source.html . I hope it helps!
At the end of every string/character array there is a null terminator character '\0' which marks the end of the string/character array.
strcpy() preforms its task until it sees the '\0' character.
printf() also preforms its task until it sees the '\0' character.
sizeof() on the other hand is not interested in the content of the array, only its allocated size (how big it is supposed to be), thus not taking into consideration where the string/character array actually ends (how big it actually is).
As opposed to sizeof(), there is strlen() that is interested in how long the string actually is (not how long it was supposed to be) and thus counts the number of characters until it reaches the end ('\0' character) where it stops (it doesn't include the '\0' character).
Better Solution is
char *strcpy(char *p,char const *q)
{
char *saved=p;
while(*p++=*q++);
return saved;
}