1

I made the following little program:

#include <stdio.h>

void strncpy(char * s, char * t, int n);

int
main()
{
    char string1[]="Learning strings";
    char string2[10];
    strncpy(string2,string1,3);
    printf("string1:%s\nstring2:%s\n",string1,string2);
    return 0;
}

void strncpy(char * s, char * t, int n)
{
    int i;
    for(i=0; i<n && t[i]!=0;i++)
        s[i]=t[i];
    s[i]=0;
}

I was trying to learn the difference between doing something like:

char greeting[]="Hello!";

And

char * farewell="Goodbye!";

And I thought my program would work with either of the two types of 'strings'(correct way of saying it?), but it only works with the first one.

Why does this happen? What's the difference between the two types?

What would I have to do to my program to be able to use strings of the second type?

YoTengoUnLCD
  • 600
  • 7
  • 15

2 Answers2

3

The statement

char greeting[] = "Hello!";

causes the compiler to work out the size of the string literal "Hello!" (7 characters including the terminating '\0'), create an array of that size, and then copy that string into that array. The result of that greeting can be modified (e.g. its characters overwritten).

The statement

char * farewell="Goodbye!";

creates a pointer that points at the first character in the string literal "Goodbye!". That string literal cannot be modified without invoking undefined behaviour.

Either greeting or farewell can be passed to any function that does not attempt to modify them. greeting can also be passed to any function which modifies it (as long as only characters greeting[0] through to greeting[6] are modified, and no others). If farewell is modified, the result is undefined behaviour.

Generally speaking, it is better to change the definition of farewell to

const char * farewell="Goodbye!";

which actually reflects its true nature (and will, for example, cause a compilation error if farewell is passed to a function expecting a non-const parameter). The fact that it is possible to define farewell as a non-const pointer while it points at (the first character of) a string literal is a historical anomaly.

And, of course, if you want farewell to be safely modifiable, declare it as an array, not as a pointer.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • Oh, I see, thanks!! I understand it now. One more question, if it's not too much of a bother: Why would you use char pointers like this if they have no advantages over char arrays? – YoTengoUnLCD Oct 04 '15 at 00:21
  • 2
    I did not suggest there are no advantages of pointers over arrays. It is possible to create a modifiable array of `const` pointers. It is significantly more difficult to achieve a comparable result without pointers. – Peter Oct 04 '15 at 00:39
1

The string literals "Hello" and "Goodbye" are stored as arrays of char such that they are allocated at program startup and released at program exit, and are visible over the entire program. They may be stored in such a way that they cannot be modified (such as in a read-only data segment). Attempting to modify the contents of a string literal results in undefined behavior, meaning the compiler isn't required to handle the situation in any particular way - it may work the way you want, it may result in a segmentation violation, or it may do so ething else.

The line

char greeting[] = "Hello"; 

allocates enough space to hold a copy of the literal and writes the contents of the literal to it. You may modify the contents of this array at will (although you can't store strings longer than "Hello" to it).

The line

char *farewell = "Goodbye";

creates a pointer and writes the address of the string literal "Goodbye" to it. Since this is a pointer to a string literal, we cannot write to the contents of the literal through that pointer.

John Bode
  • 119,563
  • 19
  • 122
  • 198