views:

189

answers:

4

Upon compiling and running this small program to reverse a string, I get a Segmentation Fault before any output occurs. Forgive me if this is an obvious question, I'm still very new to C.

#include <stdio.h>

int reverse(char string[], int length); 

int main() {
char string[] = "reversed";

  printf("String at start of main = %s", string);
  reverse(string, sizeof(string));
  printf("%s\n", string);

return 0;

}

// Reverse string 
int reverse(char string[], int length) {
 int i;
 char reversed[] = {};
 int temp;

 for(i = 0; i < length; ++i) {
 temp = string[i];
 reversed[length - i] = temp;

 }
 return 0; 
}
+5  A: 

Because of this:

First you create an array with zero elements:

char reversed[] = {};

And later you attempt to write to that array beyond its bounds:

reversed[length - i] = temp;

Update:

The above means that you need to allocate memory whose size is only known at runtime (it's length). The usual C-style way of doing this is... by pushing the burden of memory allocation to your caller:

int reverse(const char* string, char* destination, int length);

This function would write to a buffer provided by the caller, who now also must ensure that:

  1. The buffer is large enough
  2. The memory for buffer gets freed when it should be
Jon
@Moron, I think you say my initial post which was wrong. Edited it in the meantime.
Jon
There's no such thing as "array with zero elements" neither in C nor in C++. Moreover, in C there's no such initializer as `{}`. In C at least one expression is always required between the `{}`.
AndreyT
@Jon. Yes. I deleted my comment after seeing your edit.
Moron
@AndreyT: you 're correct. It's been ages since the last time I used C or allocated an array on the stack, so I didn't catch that. When saying "zero-length array", I had in mind this: `char* buf = new char[length];` which is legal C++ even if `length` is zero.
Jon
+2  A: 

While it works in this case, generally , sizeof(string) should be `strlen(string). Usually, when using char pointers, the sizeof operator will just return the size of a single pointer - and not the whole array. . In reverse(), Your reverse array is not allocated, you can allocate it like this:

char* reversed = (char*) malloc( length+1 );

We add one to the length to account for the null char at the end of the string.

mdma
Thank you. I can see exactly what was wrong now.
Leda
-1: sizeof(string) won't return the size of the pointer. It will return the size of the array in bytes. Try it.
Moron
That's right. I was thinking more of the general case. I've updated my post to reflect that.
mdma
+2  A: 

Your code is not compilable as C. The declaration

char reversed[] = {};

is invalid. There's no such thing as empty {} initializer in C language (it exists only in C++). Moreover, an empty initializer wouldn't make any sense in an array declaration of unspecified size (which makes this code non-compilable as C++ either), since there's no such thing as zero-sized array neither in C nor in C++.

Either post real code, or retag your question if this is supposed to be C++.

AndreyT
+1, I didn't even catch the tag.
Lord Torgamus
+1 for pointing out it is not 'C'.
Moron
It is however allowed in gcc -- http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html -- and doesn't even give a warning with `-Wall`.
Paul Stephenson
@Paul Stephenson: What should be a warning and what shouldn't be is always a gray area, but the fact that even `-Wall` does not result in a warning indicates one more time that the default behavior GCC is quite loosely related to real C.
AndreyT
A: 

In C you have to think carefully about the memory taken up by your variables and arrays.

When you write char reversed[] = {} you are creating a brand-new zero-sized array. (This is apparently not strictly correct C, but it is what is happening with the questioner's gcc compiler. After all, the report is of a segmentation fault at runtime rather than a syntax error at compile time.)

The statement reversed[length - i] then tries to write data to an element of the array you don't have space for, because reversed has no size.

You have two options:

  • Create a reversed array of the proper size (perhaps by using malloc as @Bob Kaufman says) and then return it from the reverse() function.
  • Reverse the string "in place", by shifting the characters around within string itself.

Reversing the string in place is likely to be preferable -- if you allocate memory dynamically then you have to worry about freeing it again, which can be a pain.

Paul Stephenson
No, you don't "create brand-new zero-sized array". In C the `{}` initializer is always a syntax error. On top of that zero-sized arrays are always prohibited in C.
AndreyT
The questioner's code compiles cleanly for me with gcc, and printing `sizeof(reversed)` outputs zero. Is this a gcc extension?
Paul Stephenson