Difference Between Char* and Char[]

Difference between char* and char[]


char str[] = "Test";

Is an array of chars, initialized with the contents from "Test", while

char *str = "Test";

is a pointer to the literal (const) string "Test".

The main difference between them is that the first is an array and the other one is a pointer. The array owns its contents, which happen to be a copy of "Test", while the pointer simply refers to the contents of the string (which in this case is immutable).

The difference between char * and char[]

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


  1. 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>
  2. 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.

  1. You are assigning a char value to a pointer-to-char variable. Your compiler should be warning you about this. (char *p3 = *p1).
  2. 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.
  3. You are using the string %s specifier with a char 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

What is the difference between char s[] and char *s?

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 makes 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.

Difference between char[] and char * in C

When using char s[] = "hello";, the char array is created in the scope of the current function, hence the memory is allocated on the stack when entering the function.

When using char *s = "hello";, s is a pointer to a constant string which the compiler saves in a block of memory of the program which is blocked for write-access, hence the segmentation fault.

Difference between char* var; and char *var;?

There is no difference in this case. However, you should prefer char *var;.

This is because the * is associated more closely with the variable name and is not part of the base type. For example, if you do this:

char* a, b;

What you have is a, a pointer-to-char, and b, a char. This is confusing! Since the * character is closer to the char keyword, we expect that the types of both variables will be pointer-to-char, but the * is actually associated only with a. (This is similar to char a[10], b; as pointed out by teppic in the comments; the [10] specifier is likewise only associated with a, and so only a will be an array.)

The correct declaration would be:

char *a, *b;

Putting the * specifier closer to the variable means that it's easy to see what's going on when you intend for one variable to be a pointer and the other not:

char *a, b;

In this case it's obvious that b was not intended to be a pointer. In the original example (char* a, b;), we don't know whether or not the programmer intended for b to be a pointer. To borrow from Douglas Crockford, all we know is that the programmer is incompetent.

Some people like to put a space before and after the *:

char * a, * b;

This falls prey to the same problem illustrated above: if b is not a pointer then the declaration (char * a, b;) may also lead to uncertainty about the programmer's intent. Therefore I suggest not placing a space between the * and the variable name1.

Any way you look at it, char* var; should be treated as bad style. It's grammatically correct according to the language specification, but leads to unreadable code because it appears to indicate that the * specifier is part of the type shared by all variables in the same declaration, when it is not. (It's akin to writing a complex function all on the same line -- it works, but it's a bad idea. There are cases where readability and maintainability supersede personal stylistic preferences, and this is one of them.)


1Personally, I prefer to put a space after the * only when dealing with function return values:

char * foo();

This is unambiguous: it's a function that returns a pointer-to-char.

char *foo();

Did the programmer mean a function that returns a pointer-to-char, or did he mean to create a pointer to a function that returns char? The language will resolve this as identical to the other prototype, but our goal is readability, and that means conveying exactly what we mean to humans, not just the compiler.

What is the difference between 'char *' and 'char (*) [100]'?

char x[100]

Array x decays to pointer:

x - pointer to the char (char *)

&x - pointer to a the array of 100 chars (char (*)[100]);

&x[0] - pointer to the char (char *)

all of those pointers reference the same start of the array, only the type is different. The type matters!!.

You should not pass the &x to the functions which expect (char *) parameters.

Why type matters?:

char x[100];

int main()
{
printf("Address of x is %p, \t x + 1 - %p\t. The difference in bytes %zu\n", (void *)(x), (void *)(x + 1), (char *)(x + 1) - (char *)(x));
printf("Address of &x is %p, \t &x + 1 - %p\t. The difference in bytes %zu\n", (void *)(&x), (void *)(&x + 1), (char *)(&x + 1) - (char *)(&x));
printf("Address of &x[0] is %p, \t &x[0] + 1 - %p\t. The difference in bytes %zu\n", (void *)(&x[0]), (void *)(&x[0] + 1), (char *)(&x[0] + 1) - (char *)(&x[0]));
}

Result:

Address of x is 0x601060,    x + 1 - 0x601061   . The difference in bytes 1
Address of &x is 0x601060, &x + 1 - 0x6010c4 . The difference in bytes 100
Address of &x[0] is 0x601060, &x[0] + 1 - 0x601061 . The difference in bytes 1

https://godbolt.org/z/SLJ6xn

What is the difference between char array and char pointer in C?

char* and char[] are different types, but it's not immediately apparent in all cases. This is because arrays decay into pointers, meaning that if an expression of type char[] is provided where one of type char* is expected, the compiler automatically converts the array into a pointer to its first element.

Your example function printSomething expects a pointer, so if you try to pass an array to it like this:

char s[10] = "hello";
printSomething(s);

The compiler pretends that you wrote this:

char s[10] = "hello";
printSomething(&s[0]);

What is the difference between char array[] and char *array?


char hello[] = {'h', 'e', 'l', 'l', 'o', '\0'};

This creates an array of 6 bytes in writable memory (on the stack if this is inside a function, in a data segment if directly at global scope or inside a namespace), to be initialised with the ASCII codes for each of those characters in turn.

char *hello = "hello";

"hello" is a string literal, which typically means:

  • the OS loader code that loads your program into memory and starts it running will have copied the text "hello\0" from your executable image into some memory that will then have been set to be read only, and

  • a separate variable named "hello" - which is of whatever size pointers are in your program (e.g. 4 bytes for 32-bit applications, 8 for 64-bit) - will exist on the stack (if the line above appears inside a function) or in writable memory segment (if the line is at global or namespace scope), and the address of the former textual data will be copied into the hello pointer.

  • you can change hello to point somewhere else (e.g. to another language's equivalent text), but normally shouldn't try to change the string literal to which the above code points hello... see below.

But in correct c++ the second should be:

const char *hello = "hello";

Yes - that's much better. For backwards compatibility, C++ has historically allowed non-const pointers to string literals, but actually modifying them wasn't guaranteed to be possible. Some compilers always, or can optionally (when asked by command line arguments), put string literals in writable memory. But, even if they are writable, changing them leads to lots of potential for errors. Say you have code like this and compiler flags to allow it to compile:

char* end = "end";
if (mixed_case_mode) end[0] = 'E';
if (s == "end") ...;

Then some completely unrelated code that does this...

std::cout << "this is the " << (x ? "start": "end");

...might start printing "End" if all mentions of "end" shared the same memory - a common and desirable optimisation. Turning this off can be quite wasteful, and while it allows this hackery to work with less unintended side effects to unrelated uses of the text, it's still very hard to reason about the code and debug when if (s == "end") might not actually be comparing s to "end".



Related Topics



Leave a reply



Submit