-1

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?

octopusgrabbus
  • 10,555
  • 15
  • 68
  • 131
Srini
  • 21
  • 2
  • 5

5 Answers5

5

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.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • What exactly is the bug you are referring to?

    I know __calloc(1,'\0')__ is not correct. Program is working fine even though this is bug. Why is it working made me ask this question. Is the behavior is Undefined?

    – Srini Mar 18 '13 at 13:18
  • @Srini: You access out of bounds. That's a bug. Code with bugs in it is *very* hard to understand. Instead, just fix the bug and the mystery will go away. (Wait until you thoroughly understand valid code before you even try to understand buggy code.) And is it really working fine? How is it not doing what you would expect it to do "working fine"? – David Schwartz Mar 18 '13 at 13:19
  • Yes it is working. It is giving me reverse of string. That's what made me think why is it working? It should not work but it is. – Srini Mar 18 '13 at 13:26
  • @Srini: Right, that's because it has a bug. Code with bugs will not do what you expect. The solution is to fix the bug and then the mystery will go away. Trying to understand buggy code is very advanced and best saved until you have a very understanding of non-buggy code because it depends heavily on subtle details that you normally can ignore. (Like what exactly are the conditions for generating a fault and how does the memory allocator actually decide what sized block to allocate and so on.) – David Schwartz Mar 18 '13 at 13:28
  • The important lesson is this: Code with bugs often will not do what you expect and can be unpredictable and hard to understand. The solution is to fix the bugs and then the mystery goes away. You can't rely on buggy code failing in predictable ways. – David Schwartz Mar 18 '13 at 13:29
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.
unwind
  • 391,730
  • 64
  • 469
  • 606
0
  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.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
0

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.

octopusgrabbus
  • 10,555
  • 15
  • 68
  • 131
  • I didn't get segfault with strcpy, i got it when is directly assigned my string to variable as in 2nd case. Now i feel that the behavior is unpredictable when i assign a less memory than required, which in my case worked fine but in general it is unpredictable. – Srini Mar 18 '13 at 14:00
  • I don't see in your original how str was defined. – octopusgrabbus Mar 18 '13 at 14:05
0

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

sdd
  • 721
  • 9
  • 23