tags:

views:

130

answers:

7

Possible Duplicate:
What is the difference between char s[] and char *s in C?

I was wondering what is the difference between

char *p1 = "some string";

and

char p2[] = "some string";

in terms of memory, can these not be treated in the same way?

e.g.

void foo(char *p);

...

foo(p1);
foo(p2);
+4  A: 

All is explained here: http://c-faq.com/aryptr/aryptr2.html

Oli Charlesworth
A: 

p1 is a pointer - so you can do pointer arithmetic, like p1++

P2 is an array, of fixed length. you can do a sizeof(p2) and it will return 12 You can't do p2++ i.e, pointer arithmetic.

kartheek
but for the function 'foo' it will in both cases have a pointer to use? even though it was passed an array | pointer
Yes, either way the function has a pointer to use. But be aware that the function must not try to modify the string pointed to by `p1`.
RBerteig
A: 

The former puts "some string" in read only memory and p1 as a pointer to the first character of that sequence of characters. You can change the value of p1 to point anywhere else.

The latter reserves space for p2 on the stack and stores its contents with "some string." You can change individual locations on the stack, but you cannot change the value of p2. For example,

p2 = "a new string" ;

is undefined behavior in C. When p2 is on the right side of an assignment statement (I am forgetting the wording used in C standard), it acts as the address of the first element of the array (of type pointer to char).

(section 6.3.2.1, para 3) " Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array , an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue."

Kizaru
A: 
char *p1 = "some string";

You are putting a pointer to char on the stack. This takes about 4-bytes of memory (but it may be different). You are then setting it to the address of a static memory location. The proper form of this statement is:

char const *p1 = "some string";

Because this enforces that the contents of the string is constant.

char p2[] = "some string";

You are declaring an array of size 12 (string length plus nul) on the stack. This is 12 bytes of data. You can modify the contents of the array, but you cannot change the pointer it degrades to when passed as a parameter, or assigned to a char*.

There are major differences in the two statements:

p1 = new char[50];  // legal
p2 = new char[50];  // illegal

p1[2] = 'a';  // illegal
p2[2] = 'a';  // legal

When passed as parameters to a function, the variables look like:

char const *p1;  // this is what p1 is
char *const p2;  // this is what p2 degrades to. It is a const pointer to the first element.
Alexander Rafferty
A: 

They are related to one another, but there's a big difference.

char p2[] = "some string";

asks for space for 12 characters and known by the name p2. On the other hand:

char *p1 = "some string";

asks for a place that holds a pointer named p1 which can point to anywhere. In this case, the pointer p1 is pointing into an array without a name, or an anonymous array of 12 characters. That anonymous array is present in the memory and the pointer p1 is tracking its location.

Ruel
+1  A: 

In your first case, ...

char* p1 = "some string";

... p is a variable of pointer type, char*. It's initialized to point to the first char in a sequence of char values somewhere. That somewhere might be in read-only memory, so you should NEVER DO THIS :-).

Instead,at least add a const for the pointee type, like ...

char const* p2 = "some string";

This way you've asked the compiler to not accept modification attempts, which would send you to Undefined Behavior land. C++ accepts the declaration of p1 only for backward compatibility with C. If you turn up your C++ compiler's warning level you will most likely get a warning about it, while the declaration of p2 is perfectly fine.

Since p2 isn't const itself, you can modify it, e.g. increment it so that it points to the second char, or whatever.

Anyway, the pointer is not very large, typically 4 or 8 bytes.

In your second case, ...

char a[] = "some string";

... a is an array that is initialized with the specified characters, plus a terminating null-byte. Each char is one byte, per definition. sizeof(a) will therefore report that a is 12 bytes, namely the 11 bytes of the specified characters, plus the null-byte.

In both C and C++, when you use a where a pointer is expected, you get an automatic conversion to pointer to the first array element, and we say informally that the array decays into pointer type. In C this happens in all cases of passing the array as argument. In C++ you can, however, pass an array by reference, avoiding the type decay.

Using the decay to advantage, you can find the number of elements of the array via ...

sizeof(a)/sizeof(*a)

where the division is unnecessary for an array of bytes, as a is, but is necessary in general for arrays of other types.

If you do that with the pointer then you just get the size of the pointer measured in units of the size of the pointee, which is seldom meaningful.

In C there's no other reasonable way to find the number of elements of an array, so the expression above is typically packaged in a macro, and one just accepts the risk of inadvertently using the macro with a pointer argument (meaningless result).

In C++ you can use the possibility of passing an array by reference to define a function that returns the number of elements of an array, like ...

typedef ptrdiff_t Size;

template< class T, Size N >
Size countOf( T const (&)[N] ) { return N; }

Calling countOf with a pointer as actual argument you just get a compilation error instead of a meaningless result.

For C++ work it's also generally convenient to define startOf and endOf functions, especially for working with algorithms from the standard library. As far as I know the first to recognize the importance of this triad of functions was Dietmar Kuhl. You can find a general implementation at my Wordpress blog, but unfortunately, as I recall, I didn't mention Dietmar there (and I'm far too lazy to fix up things! :-) ).

C++ also has some other support for arrays that C doesn't have.

In particular, as a novice you will generally be better off using std::vector from the standard library, instead of directly using "raw arrays".

Using std::vector you're much less likely to encounter the many pitfalls that are associated with raw arrays, such as e.g. the number-of-elements computation.

Cheers & hth.,

– Alf

Alf P. Steinbach
A: 

p1 is a pointer. p2 is an array, which evaluates to a pointer when used in expressions.

Perhaps an analogy is in order:

int x1 = 5;
char x2 = 5;

x1 is an int. x2 is a char, which evaluates to an int when used in expressions.

In both cases, the differences become apparent when you try to store something in the objects, and when you apply the sizeof operator to them.

R..