1

How come when I use the following method, to be used to convert all the characters in a string to uppercase,

while (*postcode) {
    *postcode = toupper(*postcode);

    postcode++;
}

Using the following argument works,

char wrong[20];
strcpy(wrong, "la1 4yt");

But the following, doesn't, despite them being the same?

char* wrong = "la1 4yt";

My program crashes in an attempt to write to an illegal address (a segfault, I presume). Is it an issue with not mallocing? Not being null-terimanted? It shouldn't be...

Through debugging I notice it crashes on the attempt to assign the first character as its uppercase.

Any help appreciated!

Humphrey Bogart
  • 7,073
  • 13
  • 51
  • 58
  • 1
    http://stackoverflow.com/questions/1614723/why-is-this-c-code-causing-a-segmentation-fault/1614739#1614739 – AnT Oct 30 '09 at 00:29
  • 1
    +1 for avoiding `*postcode = toupper(*postcode++);` or the equally bad `*postcode++ = toupper(*postcode);` :) – pmg Oct 30 '09 at 00:55
  • 1
    For crying out loud... this exact same question pops up at least twice a week. – ephemient Oct 30 '09 at 01:03
  • you were a novice once as well ephemient – Humphrey Bogart Oct 30 '09 at 02:06
  • Yes, but searching for "c segfault" on Stack Overflow alone gives you the answer within the top 5 hits. Being a novice does not exclude you from searching for and reading documentation on your own. – ephemient Oct 30 '09 at 02:55

5 Answers5

5
char* wrong = "la1 4yt";

This declares a pointer to a string constant. The constant cannot be modified, which is why your code crashes. If you wrote the more pedantic

const char* wrong = "la1 4yt"; // Better

then the compiler would catch the mistake. You should probably do this any time you declare a pointer to a string literal rather than creating an array.

This, on the other hand, allocates read/write storage for twenty characters so writing to the space is fine.

char wrong[20];

If you wanted to initialize it to the string above you could do so and then would be allowed to change it.

char wrong[20] = "la1 4yt"; // Can be modified
char wrong[]   = "la1 4yt"; // Can be modified; only as large as required
John Kugelman
  • 330,190
  • 66
  • 504
  • 555
2
char * whatever = "some cont string";

Is read-only.

ezpz
  • 11,449
  • 6
  • 36
  • 38
2

In the second variant, "la1 4yt" is a constant and therefore is in a read-only segment. Only the pointer (wrong) to the constant is writeable. That's why you get the segfault. In the first example however, everything is writable.

This one might be interesting: http://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c/

Michael
  • 8,624
  • 3
  • 36
  • 54
  • See http://c-faq.com/aryptr/aryptrequiv.html and http://c-faq.com/aryptr/aryptrparam.html and http://c-faq.com/aryptr/arypbref.html – Sinan Ünür Oct 30 '09 at 01:19
2

See Question 8.5 in the C FAQ list.

Sinan Ünür
  • 115,191
  • 15
  • 191
  • 333
1

When you do

char wrong[20] = "la1 4yt";

the compiler copies the elements of the string literal {'l', 'a', '1', ' ', '4', 'y', 't', '\0'} to the corresponding elements of the wrong array; when you do

char *wrong = "la1 4yt";

the compiler assigns to wrong the address of the string literal.

String literals are char[] (arrays of char), not const char[] ... but you cannot change them!!

Quote from the Standard:

6.4.5 String literals
6   It is unspecified whether these arrays are distinct provided
    their elements have the appropriate values. If the program
    attempts to modify such an array, the behavior is undefined.

When I use a string literal to initialize a char *, I usually also tell the compiler I will not be changing the contents of that string literal by adding a const to the definition.

const char *wrong = "la1 4yt";

Edit

Suppose you had

char *test1 = "example test";
char *test2 = "test";

And the compiler created 1 single string literal and used that single string literal to initialize both test1 and test2. If you were allowed to change the string literal ...

test1[10] = 'x';       /* attempt to change the 's' */
printf("%s\n", test2); /* print "text", not "test"! */
pmg
  • 103,426
  • 11
  • 122
  • 196