Why does my program throw a segmentation fault while using heap-allocated memory?

旧城冷巷雨未停 提交于 2019-12-08 14:52:22

问题


After writing a program to reverse a string, I am having trouble understanding why I got a seg fault while trying to reverse the string. I have listed my program below.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void reverse(char *);

int main() {
  char *str = calloc(1,'\0');
  strcpy(str,"mystring0123456789");
  reverse(str);
  printf("Reverse String is: %s\n",str);
  return 0;
}

void reverse(char *string) {
  char ch, *start, *end;
  int c=0;
  int length = strlen(string);
  start = string;
  end = string;

  while (c < length-1){
    end++;
    c++;
  }
  c=0;

  while(c < length/2){
    ch = *end;
    *end = *start;
    *start = ch;
    start++;
    end--;
    c++;
  }
}

1st Question:

Even though I have allocated only 1 byte of memory to the char pointer str (calloc(1,'\0')), and I copied a 18 bytes string mystring0123456789 into it, and it didn't throw any error and the program worked fine without any SEGFAULT.

Why did my program not throw an error? Ideally it should throw some error as it don't have any memory to store that big string. Can someone throw light on this?

The program ran perfectly and gives me output Reverse String is: 9876543210gnirtsym.

2nd Question:

If the replace the statement

strcpy(str,"mystring0123456789");

with

str="mystring0123456789\0";

the program gives segmentation fault even though I have allocated enough memory for str (malloc(100)).

Why the program throwing segmentation fault?


回答1:


Even though i have allocated only 1 byte of memory to the char pointer str(calloc(1,'\0')), and i copied a 18 bytes string "mystring0123456789" into it, and it didn't throw any error and the program worked fine without any SEGFAULT.

Your code had a bug -- of course it's not going to do what you expect. Fix the bug and the mystery will go away.

If the replace the statement
strcpy(str,"mystring0123456789");
with
str="mystring0123456789\0";
the program gives segmentation fault even though i have allocated enough memory for str (malloc(100)).

Because when you finish this, str points to a constant. This throws away the previous value of str, a pointer to memory you allocated, and replaces it with a pointer to that constant.

You cannot modify a constant, that's what makes it a constant. The strcpy function copies the constant into a variable which you can then modify.

Imagine if you could do this:

int* h = &2;

Now, if you did *h = 1; you'd be trying to change that constant 2 in your code, which of course you can't do.

That's effectively what you're doing with str="mystring0123456789\0";. It makes str point to that constant in your source code which, of course, you can't modify.




回答2:


  1. There's no requirement that it throw a segmentation fault. All that happens is that your broken code invokes undefined behavior. If that behavior has no visible effect, that's fine. If it formats the hard drive and paints the screen blue, that's fine too. It's undefined.
  2. You're overwriting the pointer value with the address of a string literal, which totally doesn't use the allocated memory. Then you try to reverse the string literal which is in read-only memory, which causes the segmentation fault.



回答3:


  1. Your program did not throw an error because, even though you did the wrong thing, ncaught you (more below). You wrote data were you were not supposed to, but you got “lucky” and did not break anything by doing this.

  2. strcpy(str,"mystring0123456789"); copies data into the place where str points. It so happens that, at that place, you are able to write data without causing a trap (this time). In contrast, str="mystring0123456789\0"; changes str to point to a new place. The place it points to is the place where "mystring0123456789\0" is stored. That place is likely read-only memory, so, when you try to write to it in the reverse routine, you get a trap.

More about 1:

When calloc allocates memory, it merely arranges for there to be some space that you are allowed to use. Physically, there is other memory present. You can write to that other memory, but you should not. This is exactly the way things work in the real world: If you rent a hotel room, you are allowed to use that hotel room, but it is wrong for you to use other rooms even if they happen to be open.

Sometimes when you trespass where you are not supposed to, in the real world or in a program, nobody will see, and you will get away with it. Sometimes you will get caught. The fact that you do not get caught does not mean it was okay.

One more note about calloc: You asked it to allocate space for one thing of zero size (the source code '\0' evaluates to zero). So you are asking for zero bytes. Various standards (such as C and Open Unix) may say different things about this, so it may be that, when you ask for zero bytes, calloc gives you one byte. However, it certainly does not give you as many bytes as you wrote with strcpy.




回答4:


It sounds like you are writing C programs having come from a dynamic language or at least a language that does automatic string handling. For lack of a more formal definition, I find C to be a language very close to the architecture of the machine. That is, you make a lot of the programming decisions. A lot of your program problems are the result of your code causing undefined behavior.You got a segfault with strcpy, because you copied memory into a protected location; the behavior was undefined. Whereas, assigning your fixed string "mystring0123456789\0" was just assigning that pointer to str.

When you implement in C, you decide whether you want to define your storage areas at compile or run-time, or decide to have storage allocated from the heap (malloc/calloc). In either case, you have to write housekeeping routines to make sure you do not exceed the storage you have defined.

Assigning a string to a pointer merely assigns the string's address in memory; it does not copy the string, and a fixed string inside quotes "test-string" is read-only, and you cannot modify it. Your program may have worked just fine, having done that assignment, even though it would not be considered good C coding practice.

There are advantages to handling storage allocations this way, which is why C is a popular language.




回答5:


Another case is that you can have a segfault when you use memory correct AND your heap became so big that your physical memory cannot manage it (without overlap with stack|text|data|bss -> link)

Proof: link, section Possible Cause #2



来源:https://stackoverflow.com/questions/15477570/why-does-my-program-throw-a-segmentation-fault-while-using-heap-allocated-memory

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!