The most straightforward answer is:
The difference here is that
char *s = "Hello world";
will place Hello world in the read-only parts of the memory and making s a pointer to that, making any writing operation on this memory illegal. While doing:
char s[] = "Hello world";
puts the literal string in read-only memory and copies the string to newly allocated memory on the stack. Thus making
s[0] = 'J';
legal.
A more lengthy explanation would include what segments the memory is stored in, and how much memory is allocated:
Example: Allocation Type: Read/Write: Storage Location: Memory Used (Bytes): =========================================================================================================== const char* str = "Stack"; Static Read-only Code segment 6 (5 chars plus '\0') char* str = "Stack"; Static Read-only Code segment 6 (5 chars plus '\0') char* str = malloc(...); Dynamic Read-write Heap Amount passed to malloc char str[] = "Stack"; Static Read-write Stack 6 (5 chars plus '\0') char strGlobal[10] = "Global"; Static Read-write Data Segment (R/W) 10
References
- What is the difference between char s[] and char *s in C?, Accessed 2014-09-03,
<https://stackoverflow.com/questions/1704407/what-is-the-difference-between-char-s-and-char-s-in-c>
- Difference between declared string and allocated string, Accessed 2014-09-03,
<https://stackoverflow.com/questions/16021454/difference-between-declared-string-and-allocated-string>
Edit
To address the edit in the question and the comment issued with it, I’ve added notes to your solution:
#include <stdio.h> int main() { char ch[] = "Hello"; /* OK; Creating an array of 6 bytes to store * 'H', 'e', 'l', 'l', 'o', '\0' */ char *p1 = ch; /* OK; Creating a pointer that points to the * "Hello" string. */ char *p2 = p1; /* OK; Creating a second pointer that also * points to the "Hello" string. */ char *p3 = *p1; /* BAD; You are assigning an actual character * (*p1) to a pointer-to-char variable (p3); * It might be more intuitive if written in * 2 lines: * char* p3; * p3 = *p1; //BAD */ printf("ch : %s\n", ch); /* OK */ printf("p1 address [%d] value is %s\n", p1, *p1); /* Bad format specifiers */ printf("p2 address [%d] value is %s\n", p2, *p2); /* Bad format specifiers */ printf("p3 address [%d] value is %s\n", p3, *p3); /* Bad format specifiers */ return 0; }
So, three major bugs.
- You are assigning a
char
value to apointer-to-char
variable. Your compiler should be warning you about this. (char *p3 = *p1
). - Depending on your compiler, you may have to use the pointer
%p
format specifier to print out an address rather than the%d
(integer) format specifier. - You are using the string
%s
specifier with achar
data type (ie:printf("%s", 'c')
is wrong). If you are printing a single character, you use the%c
format specifier, and the matching argument should be a character (ie: ‘c’, char b, etc). If you are printing an entire string, you use the%s
format specifier, and the argument is a pointer-to-char.
Examples
#include <stdio.h> int main(void) { char c = 'H'; // A character char* pC = &c; // A pointer to a single character; IS NOT A STRING char cArray[] = { 'H', 'e', 'l', 'l', 'o' }; // An array of characters; IS NOT A STRING char cString[] = { 'H', 'e', 'l', 'l', 'o', '\0' }; // An array of characters with a trailing NULL charcter; THIS IS A C-STYLE STRING // You could also replace the '\0' with 0 or NULL, ie: //char cString[] = { 'H', 'e', 'l', 'l', 'o', (char)0 }; //char cString[] = { 'H', 'e', 'l', 'l', 'o', NULL }; const char* myString = "Hello world!"; // A C-style string; the '\0' is added automatically for you printf("%s\n", myString); // OK; Prints a string stored in a variable printf("%s\n", "Ducks rock!"); // OK; Prints a string LITERAL; Notice the use of DOUBLE quotes, " " printf("%s\n", cString); // OK; Prints a string stored in a variable printf("%c\n", c); // OK; Prints a character printf("%c\n", *pC); // OK; Prints a character stored in the location that pC points to printf("%c\n", 'J'); // OK; Prints a character LITERAL; Notice the use of SINGLE quotes, ' ' /* The following are wrong, and your compiler should be spitting out warnings or even not allowing the * code to compile. They will almost certainly cause a segmentation fault. Uncomment them if you * want to see for yourself by removing the "#if 0" and "#endif" statements. */ #if 0 printf("%s\n", c); // WRONG; Is attempting to print a character as a string, similar // to what you are doing. printf("%s\n", *pC); // WRONG; Is attempting to print a character as a string. This is // EXACTLY what you are doing. printf("%s\n", cArray); // WRONG; cArray is a character ARRAY, not a C-style string, which is just // a character array with the '\0' character at the end; printf // will continue printing whatever follows the end of the string (ie: // random memory, junk, etc) until it encounters a zero stored in memory. #endif return 0; }
Code Listing – Proposed Solution
#include <stdio.h> int main() { char ch[] = "Hello"; /* OK; Creating an array of 6 bytes to store * 'H', 'e', 'l', 'l', 'o', '\0' */ char *p1 = ch; /* OK; Creating a pointer that points to the * "Hello" string. */ char *p2 = p1; /* OK; Creating a second pointer that also * points to the "Hello" string. */ char *p3 = p1; /* OK; Assigning a pointer-to-char to a * pointer-to-char variables. */ printf("ch : %s\n", ch); /* OK */ printf("p1 address [%p] value is %s\n", p1, p1); /* Fixed format specifiers */ printf("p2 address [%p] value is %s\n", p2, p2); /* Fixed format specifiers */ printf("p3 address [%p] value is %s\n", p3, p3); /* Fixed format specifiers */ return 0; }
Sample Output
ch : Hello p1 address [0x7fff58e45666] value is Hello p2 address [0x7fff58e45666] value is Hello p3 address [0x7fff58e45666] value is Hello