3

I am trying to change value of character array components using a pointer. But I am not able to do so. Is there a fundamental difference between declaring arrays using the two different methods i.e. char A[] and char *A?

I tried accessing arrays using A[0] and it worked. But I am not able to change values of the array components.

{
    char *A = "ab";
    printf("%c\n", A[0]); //Works. I am able to access A[0]
    A[0] = 'c'; //Segmentation fault. I am not able to edit A[0]
    printf("%c\n", A[0]);
}

Expected output:

a
c

Actual output:

a
Segmentation fault
AgentKuks
  • 31
  • 3

4 Answers4

3

The difference is that char A[] defines an array and char * does not.

The most important thing to remember is that arrays are not pointers.

In this declaration:

char *A = "ab";

the string literal "ab" creates an anonymous array object of type char[3] (2 plus 1 for the terminating '\0'). The declaration creates a pointer called A and initializes it to point to the initial character of that array.

The array object created by a string literal has static storage duration (meaning that it exists through the entire execution of your program) and does not allow you to modify it. (Strictly speaking an attempt to modify it has undefined behavior.) It really should be const char[3] rather than char[3], but for historical reasons it's not defined as const. You should use a pointer to const to refer to it:

const char *A = "ab";

so that the compiler will catch any attempts to modify the array.

In this declaration:

char A[] = "ab";

the string literal does the same thing, but the array object A is initialized with a copy of the contents of that array. The array A is modifiable because you didn't define it with const -- and because it's an array object you created, rather than one implicitly created by a string literal, you can modify it.

An array indexing expression, like A[0] actually requires a pointer as one if its operands (and an integer as the other). Very often that pointer will be the result of an array expression "decaying" to a pointer, but it can also be just a pointer -- as long as that pointer points to an element of an array object.

The relationship between arrays and pointers in C is complicated, and there's a lot of misinformation out there. I recommend reading section 6 of the comp.lang.c FAQ.

You can use either an array name or a pointer to refer to elements of an array object. You ran into a problem with an array object that's read-only. For example:

#include <stdio.h>
int main(void) {
    char array_object[] = "ab"; /* array_object is writable */
    char *ptr = array_object;   /* or &array_object[0] */
    printf("array_object[0] = '%c'\n", array_object[0]);
    printf("ptr[0] = '%c'\n", ptr[0]);
}

Output:

array_object[0] = 'a'
ptr[0] = 'a'
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
2

String literals are not meant to be overwritten, think of them as read-only. It is undefined behavior to overwrite the string and your computer chose to crash the program as a result. You can use an array instead to modify the string.

char A[3] = "ab";
A[0] = 'c';
Brady Dean
  • 3,378
  • 5
  • 24
  • 50
2

String literals like "ab" are supposed to be immutable, like any other literal (you can't alter the value of a numeric literal like 1 or 3.1419, for example). Unlike numeric literals, however, string literals require some kind of storage to be materialized. Some implementations (such as the one you're using, apparently) store string literals in read-only memory, so attempting to change the contents of the literal will lead to a segfault.

The language definition leaves the behavior undefined - it may work as expected, it may crash outright, or it may do something else.

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

Is there a fundamental difference between declaring arrays using the two different methods i.e. char A[] and char *A?

Yes, because the second one is not an array but a pointer.

The type of "ab" is char /*readonly*/ [3]. It is an array with immutable content. So when you want a pointer to that string literal, you should use a pointer to char const:

char const *foo = "ab";

That keeps you from altering the literal by accident. If you however want to use the string literal to initialize an array:

char foo[] = "ab";  // the size of the array is determined by the initializer
                   //  here: 3 - the characters 'a', 'b' and '\0'

The elements of that array can then be modified.

Array-indexing btw is nothing more but syntactic sugar:

foo[bar];  /* is the same as */  *(foo + bar);

That's why one can do funny things like

"Hello!"[2];  /* 'l'   but also */  2["Hello!"];  // 'l'
Swordfish
  • 12,971
  • 3
  • 21
  • 43