what makes difference with these two programs in C
I have two very similar programs, as follows.
Program A: no problem when running,
#include <string.h>
#include <stdio.h>
typedef struct p_struct{
unsigned char* pulist;
int length;
} list_type;
int get_struct(list_type* l)
{
memset(l->pulist, 0, 4);
l->length=4;
}
int main ()
{
list_type str;
get_struct(&str);
}
Program B: has an additional function call, still compiles, but c开发者_如何学运维rashes with run-time error "Segmentation fault" with gcc.
#include <string.h>
#include <stdio.h>
typedef struct p_struct{
unsigned char* pulist;
int length;
} list_type;
int get_struct(list_type* l)
{
memset(l->pulist, 0, 4);
l->length = 4;
}
int get_struct_a()
{
list_type str;
get_struct(&str);
}
int main ()
{
get_struct_a();
}
I am really struggling to figure out the problem here. Can anyone tell me what causes "Segmentation error"? Also, why program B gives "Segmentation fault" error, while program A does not?
You're not allocating memory for the pulist
member of your structure. Hence when you memset
it, you're overwriting some other memory somewhere else. It's just luck that in the second case the memory you overwrite happens not to give a segfault, but you're still corrupting the memory.
memset(l->pulist, 0, 14);
Is probably what's crashing it. You're not allocating any memory for l->pulist
before you try to use it as a pointer to some memory.
This
memset(l->pulist, 0, 4);
Should also crash, but it's working by chance.
What's happening is you're allocating one of those struct
s on the stack, and all the members have some random garbage value in them (the value that happened to be in the memory it got allocated). Then you're trying to use one of these random values as a pointer, and telling memset
, "go overwrite 14 bytes at this random location with 0s." You can see why that would cause problems. But since the pointer is random, it doesn't always cause problems.
You'll need to do something like
l->pulist = malloc(size);
To make it a valid pointer before using it in operations like that.
You never initialize pulist
to anything, so it is pointing just anywhere. It is just pure coincidence that it crashes in one case, but not the other.
A segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (for example, attempting to write to a read-only location, or to overwrite part of the operating system).
A few causes of a segmentation fault can be summarized as follows:
attempting to execute a program that does not compile correctly. Note that most compilers will not output a binary given a compile-time error.
- a buffer overflow.
- using uninitialized pointers.
- dereferencing NULL pointers.
- attempting to access memory the program does not own.
- attempting to alter memory the program does not own (storage violation).
- exceeding the allowable stack size (possibly due to runaway recursion or an infinite loop)
Generally, segmentation faults occur because: a pointer is either NULL, points to random memory (probably never initialized to anything), or points to memory that has been freed/deallocated/"deleted".
I would say the the struct member pulist is an uninitialized pointer. Befor you use memset you need to allocate some memory for this member.
You haven't initialized your pulist
member to point anywhere meaningful; it just contains a random bit string. In program A, that random bit string corresponds to a memory address that just happens to be writable. In program B, it doesn't.
Both programs are equally wrong. When you create your list_type
object, you need to explicitly set the pulist
member to point to a buffer that you own.
精彩评论