469,904 Members | 2,143 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,904 developers. It's quick & easy.

A question on string literals

char *str1 = "Hello";
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

Is it legal to modify str1, arr1 and arr2 ?

Nov 15 '05 #1
52 2685
1.char *str1 = "Hello";

Generally the string literals would be stored in the read only data
section of the resulting object code, post compilation. So, modifying
the contents of the memory location addressed by "str1" would result in
seg fault. This might be compiler dependent though.

Although, "str1" itself can be modified.

The following is valid:
char *str1 = "Hello";
str1 = 0; // Allowed

2.char arr1[] = { "Hello" };

Contents of the memory addressed by "arr1" can be modified. "arr1"
itself cannot be modified.

That is the following is invalid:
char arr1[] = { "Hello" };
arr1 = 0; // Not allowed.

3. char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

Same comments as above for "arr2" hold true here.

-Sriram.

Nov 15 '05 #2
junky_fel...@yahoo.co.in wrote:
char *str1 = "Hello";
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

Is it legal to modify str1, arr1 and arr2 ?


This is a FAQ. Read Question 1.32

http://www.eskimo.com/~scs/C-faq/faq.html

Krishanu

Nov 15 '05 #3

ju**********@yahoo.co.in wrote:
char *str1 = "Hello";
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

Is it legal to modify str1, arr1 and arr2 ?


FAQ 6.2 should be a good place to start.

To quote the draft:

The declaration
char arr1[] = { "Hello" };
defines a 'plain' char array object (of unknown size) `arr1' whose
elements
are initialized with character string literal. Array contents
are modifiable. This declaration is identical to
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };
as well as
char arr3[] = { 'H', 'e', 'l', 'l', 'o', '\0' };

OTOH,
char *str1 = "Hello";
defines str1 with type 'pointer to char' and initializes it
to point to an object with type 'array of char' with length
6 whose elements are initialized with a character string literal.
If an attempt is made to use p to modify the contents of the array,
the behavior is undefined.

Nov 15 '05 #4
ju**********@yahoo.co.in wrote:

char arr2[] = { 'H', 'e', 'l', 'l', 'o' };


This case has no string literal, in fact no string at all. It's an
array of five characters without a null terminator.


Brian
Nov 15 '05 #5
"Default User" <de***********@yahoo.com> wrote in message
news:3l*************@individual.net...
ju**********@yahoo.co.in wrote:
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };


This case has no string literal, in fact no string at all. It's an
array of five characters without a null terminator.


No, it's an array of six characters and it DOES have a null terminator.
Nov 15 '05 #6
Mark wrote:
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };


This case has no string literal, in fact no string at all. It's an
array of five characters without a null terminator.


No, it's an array of six characters and it DOES have a null terminator.


% cat foo.c
#include <stdio.h>

int main(void)
{
char foo[] = { 'H', 'e', 'l', 'l', 'o' };

printf("%u\n", (unsigned)(sizeof foo));
return 0;
}
% gcc -Wall -ansi -pedantic foo.c
% ./a.out
5

Nov 15 '05 #7
Mark wrote:
"Default User" <de***********@yahoo.com> wrote in message
news:3l*************@individual.net...
ju**********@yahoo.co.in wrote:
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };


This case has no string literal, in fact no string at all. It's an
array of five characters without a null terminator.


No, it's an array of six characters and it DOES have a null
terminator.


Wanna bet?

Brian
Nov 15 '05 #8
On 9 Aug 2005 02:09:27 -0700, in comp.lang.c ,
ju**********@yahoo.co.in wrote:
char *str1 = "Hello";
you can modify str1 (change where it points) but not what it currently
points to.
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };


These are identical objects. You can modify what is inside them, but
not change arr1 or arr2.
--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>

----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Nov 15 '05 #9


Mark McIntyre wrote:
On 9 Aug 2005 02:09:27 -0700, in comp.lang.c ,
ju**********@yahoo.co.in wrote:

char *str1 = "Hello";

you can modify str1 (change where it points) but not what it currently
points to.

char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

These are identical objects. [...]


To quote Default User, elsethread: "Wanna bet?"

--
Er*********@sun.com

Nov 15 '05 #10
Mark McIntyre <ma**********@spamcop.net> writes:
On 9 Aug 2005 02:09:27 -0700, in comp.lang.c ,
ju**********@yahoo.co.in wrote:
char *str1 = "Hello";


you can modify str1 (change where it points) but not what it currently
points to.
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };


These are identical objects. You can modify what is inside them, but
not change arr1 or arr2.


No, they're not identical. arr1 has a '\0' terminator; arr2 doesn't.

You can modify the values of arr1 and arr2, since they're (non-const)
array objects. (Their names decay to pointers in most contexts, and
of course you can't change the values of the pointers to which they
decay.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #11

Mark wrote:
"Default User" <de***********@yahoo.com> wrote in message
news:3l*************@individual.net...
ju**********@yahoo.co.in wrote:
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };


This case has no string literal, in fact no string at all. It's an
array of five characters without a null terminator.


No, it's an array of six characters and it DOES have a null terminator.


Only if the compiler is busticated. Let's try this again:

char arr2[] = {72, 101, 108, 108, 111};

How many elements are in the array? Is there a 0-valued element
anywhere in the array?

Nov 15 '05 #12
ju**********@yahoo.co.in wrote:

char *str1 = "Hello";
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

Is it legal to modify str1, arr1 and arr2 ?


Depends on what you mean.

/* BEGIN new.c */

#include <stdio.h>
#include <string.h>

int main(void)
{
char *str1 = "Hello";
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

strcpy(arr1, ++str1);
strcpy(arr2, arr1);
puts(str1);
puts(arr1);
puts(arr2);
return 0;
}

/* END new.c */
--
pete
Nov 15 '05 #13
pete wrote:

char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

strcpy(arr2, arr1); puts(arr2);

Please read the other posts from earlier in the day about arr2 NOT
being a string. Don't do stringy things with such a monster.


Brian
Nov 15 '05 #14
On Wed, 10 Aug 2005 00:28:33 +0000, Default User wrote:
pete wrote:
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

strcpy(arr2, arr1);
puts(arr2);

Please read the other posts from earlier in the day about arr2 NOT
being a string. Don't do stringy things with such a monster.


In this case, if we replace some of the lines you snipped,
char *str1 = "Hello";
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

strcpy(arr1, ++str1);
strcpy(arr2, arr1);
puts(str1);
puts(arr1);
puts(arr2);


we see that since str1 was first incremented, arr2 contains sufficient
space to hold the copied string.

--
http://members.dodo.com.au/~netocrat

Nov 15 '05 #15
Mark wrote:
"Default User" <de***********@yahoo.com> wrote in message
news:3l*************@individual.net...
ju**********@yahoo.co.in wrote:

char arr2[] = { 'H', 'e', 'l', 'l', 'o' };


This case has no string literal, in fact no string at all. It's an
array of five characters without a null terminator.

No, it's an array of six characters and it DOES have a null terminator.

Nonsense.

#include <stdio.h>
int main(void) {
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };
printf("%d\n", (int)sizeof arr2);
return 0;
}

Prints..
5

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #16
Default User wrote:

pete wrote:
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

strcpy(arr2, arr1);

puts(arr2);


Please read the other posts from earlier in the day about arr2 NOT
being a string. Don't do stringy things with such a monster.


I used the array correctly.
Whether or not arr2 initially contains a string,
has nothing to do with whether or not arr2 can be modified
as per OP's question, and it has nothing to do with
whether or not arr2 can be a destination for strcpy.

--
pete
Nov 15 '05 #17
pete wrote:
Default User wrote:

Please read the other posts from earlier in the day about arr2 NOT
being a string. Don't do stringy things with such a monster.


I used the array correctly.

Ah, ok. I see the ++ now that I look at it more carefully.

Brian
Nov 15 '05 #18
On Tue, 09 Aug 2005 17:55:08 -0400, in comp.lang.c , Eric Sosman
<er*********@sun.com> wrote:


Mark McIntyre wrote:
On 9 Aug 2005 02:09:27 -0700, in comp.lang.c ,
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

These are identical objects. [...]


To quote Default User, elsethread: "Wanna bet?"


and I'd lose, of course. They're identical in that you can modify them
both in much the same way. I forgot that arr1 has an extra element.
--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>

----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Nov 15 '05 #19
In article <11**********************@g14g2000cwa.googlegroups .com>, Sriram Rajagopalan wrote:
1.char *str1 = "Hello";

Generally the string literals would be stored in the read only data
section of the resulting object code, post compilation. So, modifying
the contents of the memory location addressed by "str1" would result in
seg fault. This might be compiler dependent though.
That specific behavior is compiler-dependent, but modifying string literals
is not allowed by the Standard (any of them). Since this newsgroup deals with
the standards and how they relate to various programs and programming constructs,
it's better to say that the behavior is undefined.

Although, "str1" itself can be modified.

The following is valid:
char *str1 = "Hello";
str1 = 0; // Allowed
To be more clear, you might replace 0 with NULL. This is just a stylistic issue.

2.char arr1[] = { "Hello" };

Contents of the memory addressed by "arr1" can be modified. "arr1"
itself cannot be modified.

That is the following is invalid:
char arr1[] = { "Hello" };
arr1 = 0; // Not allowed.
No, that is still allowed: The array 'decomposes' into a pointer and
you can modify a non-const-qualified pointer at will.

What's giving me fits is what that is a pointer /to/. I don't think the
line of code is valid, in other words. It would be just fine if it was
defined like this:

char *arr1[] = { "Hello" };

As it stands, however, I don't think the definition is valid.

3. char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

Same comments as above for "arr2" hold true here.
Well, no. arr2 is an array of char of size 5, but it cannot be used
as a string by most standard string-handing functions as it lacks
nul-termination. An array can decompose into a pointer to the first
element under certain conditions (such as when it is passed into or
returned from a function) and that array would decompose into a
pointer to char. Since nothing is const-qualified, you can modify that
array's contents and the value of the pointer it can decompose into.

Thus, both of these are legal:

arr2[1] = 'a'; /* The array is now 'Hallo' */
arr2 = NULL; /* The array is now unreachable. */

-Sriram.


----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Nov 15 '05 #20
Chris Barts wrote:

In article <11**********************@g14g2000cwa.googlegroups .com>,
Sriram Rajagopalan wrote:
That is the following is invalid:
char arr1[] = { "Hello" };
arr1 = 0; // Not allowed.


No, that is still allowed: The array 'decomposes' into a pointer and
you can modify a non-const-qualified pointer at will.
Thus, both of these are legal:


Sriram Rajagopalan is right.
The result of the array to pointer conversion is not an lvalue.
Thus, both of these are legal:
arr2[1] = 'a'; /* The array is now 'Hallo' */
arr2 = NULL; /* The array is now unreachable. */


Try to compile it.

--
pete
Nov 15 '05 #21
Chris Barts wrote:
In article <11**********************@g14g2000cwa.googlegroups .com>, Sriram
Rajagopalan wrote:

char arr1[] = { "Hello" };
arr1 = 0; // Not allowed.

Correct.

No, that is still allowed: The array 'decomposes' into a pointer
Incorrect. Such decay happens only in value contexts, and this is not such a
context.
and
you can modify a non-const-qualified pointer at will.
Arrays are not pointers.
What's giving me fits is what that is a pointer /to/.
It isn't a pointer. It's an array.
I don't think the
line of code is valid, in other words. It would be just fine if it was
defined like this:

char *arr1[] = { "Hello" };


Nothing wrong with the definition, of course, but:

arr1 = NULL; /* wrong */

would still be an error.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
mail: rjh at above domain
Nov 15 '05 #22
Richard Heathfield wrote:

Chris Barts wrote:
In article <11**********************@g14g2000cwa.googlegroups .com>, Sriram
Rajagopalan wrote:

char arr1[] = { "Hello" };
arr1 = 0; // Not allowed.

Correct.

No, that is still allowed: The array 'decomposes' into a pointer


Incorrect. Such decay happens only in value contexts,
and this is not such a context.


I think it does happen. The standard describes the conversion
as something that happens except in three cases.

N869
6.3.2 Other operands
6.3.2.1 Lvalues and function designators
[#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.

arr1 = NULL; /* wrong */

would still be an error.


What kind of an error?

The name of an array, if not converted,
fits the K&R and the standards' descriptions of lvalue.

Regarding
arr1 = NULL;
my compiler says: error C2106: '=' : left operand must be l-value

--
pete
Nov 15 '05 #23
pete wrote:
Richard Heathfield wrote:

Chris Barts wrote:
> In article <11**********************@g14g2000cwa.googlegroups .com>,
> Sriram Rajagopalan wrote:
>>
>> char arr1[] = { "Hello" };
>> arr1 = 0; // Not allowed.
Correct.
>
> No, that is still allowed: The array 'decomposes' into a pointer


Incorrect. Such decay happens only in value contexts,
and this is not such a context.


I think it does happen. The standard describes the conversion
as something that happens except in three cases.


It's a constraint violation: "an assignment operator shall have a modifiable
lvalue as its left operand". Therefore, a diagnostic message is required,
and the program is considered incorrect. The Standard does not define how
incorrect programs are translated, or how they behave.
arr1 = NULL; /* wrong */

would still be an error.


What kind of an error?


A constraint violation.
The name of an array, if not converted,
fits the K&R and the standards' descriptions of lvalue.

Regarding
arr1 = NULL;
my compiler says: error C2106: '=' : left operand must be l-value


This is in accordance with the Standard, which requires a diagnostic for
that code.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
mail: rjh at above domain
Nov 15 '05 #24
Chris Barts wrote:
[ snip ]

That is the following is invalid:
char arr1[] = { "Hello" };
arr1 = 0; // Not allowed.

No, that is still allowed: The array 'decomposes' into a pointer and
you can modify a non-const-qualified pointer at will.

No, that is not allowed. arr1 is an array and you attempt to assign to
it. You cannot assign anything to an array.
What's giving me fits is what that is a pointer /to/. I don't think the
line of code is valid, in other words. It would be just fine if it was
defined like this:

char *arr1[] = { "Hello" };

As it stands, however, I don't think the definition is valid.
It is perfectly valid. It initializes arr1[0] (a pointer) with the
address of the literal "Hello".
3. char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

Same comments as above for "arr2" hold true here.

Well, no. arr2 is an array of char of size 5, but it cannot be used
as a string by most standard string-handing functions as it lacks
nul-termination. An array can decompose into a pointer to the first
element under certain conditions (such as when it is passed into or
returned from a function) and that array would decompose into a
pointer to char. Since nothing is const-qualified, you can modify that
array's contents and the value of the pointer it can decompose into.

I believe you have a concept problem here. The name of an array will
'decay' to the address of its first element in 'rvalue' cases. Used in
an lvalue context, the array name does not decay. It is still an array
and you cannot assign anything to an array.
Thus, both of these are legal:

arr2[1] = 'a'; /* The array is now 'Hallo' */
arr2 = NULL; /* The array is now unreachable. */

Still not. You cannot assign to an array.

Do you ever try to compile any of this stuff? You might learn something
and avoid some embarrassment.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #25
pete <pf*****@mindspring.com> writes:
Richard Heathfield wrote:

[...]
arr1 = NULL; /* wrong */

would still be an error.


What kind of an error?

The name of an array, if not converted,
fits the K&R and the standards' descriptions of lvalue.

Regarding
arr1 = NULL;
my compiler says: error C2106: '=' : left operand must be l-value


The error message is slightly misleading. arr1 is an lvalue; the
problem is that it's not a modifiable lvalue.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #26
Keith Thompson wrote:

pete <pf*****@mindspring.com> writes:
Richard Heathfield wrote:

[...]
arr1 = NULL; /* wrong */

would still be an error.


What kind of an error?

The name of an array, if not converted,
fits the K&R and the standards' descriptions of lvalue.

Regarding
arr1 = NULL;
my compiler says: error C2106: '=' : left operand must be l-value


The error message is slightly misleading. arr1 is an lvalue; the
problem is that it's not a modifiable lvalue.


Why isn't arr1 converted to a nonlvalue pointer in
arr1 = NULL;
as per
N869, 6.3.2.1 Lvalues and function designators, [#3]
?

--
pete
Nov 15 '05 #27
Richard Heathfield wrote:

pete wrote:
Richard Heathfield wrote:

Chris Barts wrote:

> In article <11**********************@g14g2000cwa.googlegroups .com>,
> Sriram Rajagopalan wrote:
>>
>> char arr1[] = { "Hello" };
>> arr1 = 0; // Not allowed.

Correct.

>
> No, that is still allowed: The array 'decomposes' into a pointer

Incorrect. Such decay happens only in value contexts,


Where are you getting that from?

--
pete
Nov 15 '05 #28
pete <pf*****@mindspring.com> writes:
Keith Thompson wrote:

pete <pf*****@mindspring.com> writes:
> Richard Heathfield wrote:

[...]
>> arr1 = NULL; /* wrong */
>>
>> would still be an error.
>
> What kind of an error?
>
> The name of an array, if not converted,
> fits the K&R and the standards' descriptions of lvalue.
>
> Regarding
> arr1 = NULL;
> my compiler says: error C2106: '=' : left operand must be l-value


The error message is slightly misleading. arr1 is an lvalue; the
problem is that it's not a modifiable lvalue.


Why isn't arr1 converted to a nonlvalue pointer in
arr1 = NULL;
as per
N869, 6.3.2.1 Lvalues and function designators, [#3]
?


Why do you think it isn't?

Assuming arr1 is an array object:
int arr1[10];
arr1 = NULL;
we know the assignment is illegal. If arr1 is implicitly converted to
a non-lvalue pointer value, that would explain why it's illegal.

One compiler I tried complains "incompatible types in assignment",
which doesn't really fit with this theory, but as long as the compiler
produces a diagnostic that doesn't really matter.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #29
pete wrote:
Richard Heathfield wrote:

pete wrote:
>> > No, that is still allowed: The array 'decomposes' into a pointer
>>
>> Incorrect. Such decay happens only in value contexts,


Where are you getting that from?


Well, I must admit I was getting it from Chris Torek's constant incantations
of "The Rule", and perhaps I was over-interpreting it. The fact remains
that the conversion you expect is not guaranteed by the Standard for the
simple reason that the code itself violates a constraint.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
mail: rjh at above domain
Nov 15 '05 #30
>> Richard Heathfield wrote:
> [Array-to-pointer] decay happens only in value contexts,
pete wrote:
Where are you getting that from?

In article <dd**********@nwrdmz01.dmz.ncs.ea.ibs-infra.bt.com>
Richard Heathfield <so************@not.even.this.one.invalid> wrote:Well, I must admit I was getting it from Chris Torek's constant incantations
of "The Rule", and perhaps I was over-interpreting it. The fact remains
that the conversion you expect is not guaranteed by the Standard for the
simple reason that the code itself violates a constraint.


Indeed, "The Rule" and the C standards (both of them) are not
literally the same -- but they *are* isomorphic, i.e., both give
the same result. I think my formulation is easier to understand,
as well, because we need the idea of "value context" vs "object
context" in the first place, so that we can figure why:

int x, b;
...
x = b;

copies b's *value* to the *object* named x.

If x used to be 3 before the assignment, and b is 7, why does this
set x to 7, instead of setting b to 3, or setting 3 to 7, or setting
7 to 3? (Of course, only two of those four possibilities even make
sense.) The answer is that the "=" operator demands an object on
its left, and a value on its right. The context on the left of
the "=" is an "object context", and the context on the right is a
"value context". Put down a value when something needs a value
and there is no problem:

x = 3;

Here x is an object and 3 is a value (of the correct type), so this
sets x to 3. Name an object on the right, though, and the operation
automatically fetches the object's value:

x = b;

so if b was 7, x becomes 7 too.

Once you understand the idea of "object context" and "value context",
you simply have to memorize which operators have which context(s):

&foo - object context
sizeof foo - object (or maybe even "sizeof") context
foo + bar - two value contexts
foo = bar - one object context, one value context
++foo - object context

and so on.

Given all of that, applying The Rule becomes easy, and whenever
the result is not "this makes no sense and a diagnostic is required",
it gives the same result as the more complicated way the C standards
put it.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #31
Richard Heathfield <in*****@address.co.uk.invalid> writes:
pete wrote:
Richard Heathfield wrote:

pete wrote:

>> > No, that is still allowed: The array 'decomposes' into a pointer
>>
>> Incorrect. Such decay happens only in value contexts,


Where are you getting that from?


Well, I must admit I was getting it from Chris Torek's constant incantations
of "The Rule", and perhaps I was over-interpreting it. The fact remains
that the conversion you expect is not guaranteed by the Standard for the
simple reason that the code itself violates a constraint.


The reasoning here is backwards. We know that the
conversion must take place, and it is the nature of the
required conversion that gives rise to the constraint
violation. Consider the statement:

array = 0;

and these questions:

Is 'array' a string literal used to initialize
an array? No it is not.

Is 'array' the operand of the unary & operator?
No it is not.

Is 'array' operand of the sizeof operator?
No it is not.

Does the expression 'array' have type "array of type"?
Yes it does.

Therefore 6.3.2.1 p3 (which pete posted) applies:

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

Now consider the effect of putting in for the "...." at
sentence end the text "is a modifiable lvalue" (rather than
the text actually written, "is not an lvalue"). Then the
assignment

array = 0;

would satisfy the 'Constraints' of 6.5.16 p2, and so would
not (under the hypothesis) be a constraint violation.

It is the final four words of 6.3.2.1 p3 that determine the
constraint violation in this case.
Nov 15 '05 #32
Keith Thompson <ks***@mib.org> writes:
pete <pf*****@mindspring.com> writes:
Richard Heathfield wrote:

[...]
arr1 = NULL; /* wrong */

would still be an error.


What kind of an error?

The name of an array, if not converted,
fits the K&R and the standards' descriptions of lvalue.

Regarding
arr1 = NULL;
my compiler says: error C2106: '=' : left operand must be l-value


The error message is slightly misleading. arr1 is an lvalue;


Not here it isn't. See 6.3.2.1 p3.
Nov 15 '05 #33
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
It is the final four words of 6.3.2.1 p3 that determine the
constraint violation in this case.


Small correction - the final four words of the first
sentence. The paragraph in the standard has a second
sentence that was not quoted (about array objects
with register storage class).
Nov 15 '05 #34
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
pete <pf*****@mindspring.com> writes:
> Richard Heathfield wrote:

[...]
>> arr1 = NULL; /* wrong */
>>
>> would still be an error.
>
> What kind of an error?
>
> The name of an array, if not converted,
> fits the K&R and the standards' descriptions of lvalue.
>
> Regarding
> arr1 = NULL;
> my compiler says: error C2106: '=' : left operand must be l-value


The error message is slightly misleading. arr1 is an lvalue;


Not here it isn't. See 6.3.2.1 p3.


You're right.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #35
Chris Torek <no****@torek.net> writes:
Richard Heathfield wrote:
>> [Array-to-pointer] decay happens only in value contexts,
pete wrote:
Where are you getting that from?


In article <dd**********@nwrdmz01.dmz.ncs.ea.ibs-infra.bt.com>
Richard Heathfield <so************@not.even.this.one.invalid> wrote:
Well, I must admit I was getting it from Chris Torek's constant incantations
of "The Rule", and perhaps I was over-interpreting it. The fact remains
that the conversion you expect is not guaranteed by the Standard for the
simple reason that the code itself violates a constraint.


Indeed, "The Rule" and the C standards (both of them) are not
literally the same -- but they *are* isomorphic, i.e., both give
the same result. I think my formulation is easier to understand,
as well, because we need the idea of "value context" vs "object
context" in the first place, so that we can figure why:

int x, b;
...
x = b;

copies b's *value* to the *object* named x.

If x used to be 3 before the assignment, and b is 7, why does this
set x to 7, instead of setting b to 3, or setting 3 to 7, or setting
7 to 3? (Of course, only two of those four possibilities even make
sense.) The answer is that the "=" operator demands an object on
its left, and a value on its right. The context on the left of
the "=" is an "object context", and the context on the right is a
"value context". Put down a value when something needs a value
and there is no problem:

x = 3;

Here x is an object and 3 is a value (of the correct type), so this
sets x to 3. Name an object on the right, though, and the operation
automatically fetches the object's value:

x = b;

so if b was 7, x becomes 7 too.

Once you understand the idea of "object context" and "value context",
you simply have to memorize which operators have which context(s):

&foo - object context
sizeof foo - object (or maybe even "sizeof") context
foo + bar - two value contexts
foo = bar - one object context, one value context
++foo - object context

and so on.


A difficulty with the above is that the operand of sizeof
isn't an object context: any expression can be used as the
operand of sizeof [1], not just an lvalue expression. Also,
note a difference in behavior: usually,

sizeof &*p == sizeof p

if 'p' is a pointer (eg, to int), but (again, usually)

sizeof &*array != sizeof array

if 'array' is an array, even though both equalities hold if
the 'sizeof's are taken out.

Of course, it's important to understand the distinction
between "object context" and "value context", but trying to
use that distinction to explain what happens with arrays in
conjunction with sizeof seems like a strain. An expression
of array type simply behaves differently than expressions of
other types. It isn't that hard to remember the exception
cases for when an array expression doesn't convert to a
pointer; there are after all only three of them.

Incidentally, note that the distinction between object
context and value context also doesn't work very well for
the third exceptional case for array-type non-conversion,
which is that of a string literal used to initialize an
array:

char *p = "blah"; /* conversion */
char s[] = "blah"; /* no conversion */

On the face of it both instances of "blah" look like they
ought to be object contexts.

=====
[1] Subject to the usual need for parentheses around
operators of lower precedence, and the need to avoid
function types and incomplete types.

Given all of that, applying The Rule becomes easy, and whenever
the result is not "this makes no sense and a diagnostic is required",
it gives the same result as the more complicated way the C standards
put it.


It seems easier (at least to me) to remember that array
expressions always convert to pointers, except when they are
the operand of sizeof or address-of operators (or string
literals used to initialize an array).

That the conversion yields a value, rather than being an
object designator, suffices to explain (and without having
to remember anything extra) why an array expression can't be
assigned to or incremented, any more than the value of a
function call

f() = 3; /* WRONG! */
f() ++; /* WRONG! */

can be assigned to or incremented. Just knowing that
the array conversion is happening is enough to explain
and understand the behavior here.

Certainly there are places where the C standards documents
give explanations that are more complicated than they need
to be. IMO however the rule for when arrays are or aren't
converted to pointers isn't one of them.
Nov 15 '05 #36

Keith Thompson wrote:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
pete <pf*****@mindspring.com> writes:
> Richard Heathfield wrote:
[...]
>> arr1 = NULL; /* wrong */
>>
>> would still be an error.
>
> What kind of an error?
>
> The name of an array, if not converted,
> fits the K&R and the standards' descriptions of lvalue.
>
> Regarding
> arr1 = NULL;
> my compiler says: error C2106: '=' : left operand must be l-value

The error message is slightly misleading. arr1 is an lvalue;


Not here it isn't. See 6.3.2.1 p3.


You're right.


I also got the similar warning "In this statement, "arr1" is not an
lvalue ,
but occurs in a context that requires one. (needlvalue)"

It looks that arr1 is being converted to (char *)arr1, which is not an
lvalue.
If I do *arr1 = NULL; It compiles without any warning/error.

I always have a confusion that why array is called "non modifiable
lvalue",
because we can always modify the contents of an array.
The only reason that
arr1 = NULL; should not be allowed because arr1 is an array object and
RHS is not compatible with it. That might be the reason, standard
doesn't
allow modifying array object in this manner and to prevent this made it
non modifiable lvalue.

Nov 15 '05 #37
Joe Wright <jw*****@comcast.net> writes:
[snip]
The name of an array will
'decay' to the address of its first element in 'rvalue' cases. Used in
an lvalue context, the array name does not decay. It is still an array
and you cannot assign anything to an array.


Technically incorrect. An array (or any expression of array
type) will convert to a pointer to the first element in
(most) lvalue contexts as well as rvalue contexts. The only
exception (that is an lvalue context) is the operand of the
address-of operator. See 6.3.2.1 p3.

It's true that an array can't be assigned to, but that's
because the array-to-pointer conversion yields a value
rather than an object designator. It's exactly analogous to
trying to use, eg, the result of a function call:

f() = 3; /* WRONG! */
f() ++; /* WRONG! */

These attempts fail for the same reason that using arrays
fail: the result of the expression is a value, much like
3+4, and values aren't eligible for being assigned to.
Nov 15 '05 #38
In article <dd********@news2.newsguy.com>,
Chris Torek <no****@torek.net> wrote:
Once you understand the idea of "object context" and "value context",
you simply have to memorize which operators have which context(s):

&foo - object context
sizeof foo - object (or maybe even "sizeof") context
foo + bar - two value contexts
foo = bar - one object context, one value context
++foo - object context

and so on.


Memorize? I've always found that taking a half-second to think about
what the operator does to its operand is enough to work out the context
that that operand is being used in.
(Thinking neurons are a lot cheaper than memorization neurons, so think
where possible and only memorize where necessary. Habit neurons are
even cheaper, but they're not very useful here.)
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
[A]n "outrage" is when someone beats up innocent bystanders in the streets,
not when your favourite programming language has a feature you dislike.
--Richard Bos in comp.lang.c
Nov 15 '05 #39
ju**********@yahoo.co.in writes:
[...
I always have a confusion that why array is called "non modifiable
lvalue", because we can always modify the contents of an array. The
only reason that arr1 = NULL; should not be allowed because arr1 is
an array object and RHS is not compatible with it. That might be the
reason, standard doesn't allow modifying array object in this manner
and to prevent this made it non modifiable lvalue.


An array isn't (necessarily) a non-modifiable lvalue.

C99 6.3.2.1p3 says:

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. If the array
object has register storage class, the behavior is undefined.

In
arr1 = NULL;
(assuming arr1 is the name of an array object), arr1 doesn't match any
of the exceptions above, so it's converted to a pointer to the initial
element of arr1 -- and this pointer value is explicitly not an lvalue.

(I was mistaken upthread when I said that it's an lvalue but not a
modifiable lvalue; it's not an lvalue at all.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #40
Chris Torek wrote:
[ snip ]
Once you understand the idea of "object context" and "value context",
you simply have to memorize which operators have which context(s):

&foo - object context
sizeof foo - object (or maybe even "sizeof") context
foo + bar - two value contexts
foo = bar - one object context, one value context
++foo - object context

and so on.

I know you Chris and I love you like a brother but given..
int foo = 2, bar = 3;

&foo - is the address of foo, a 'value' of type (int*)
sizeof foo - is a value (4 at my house) of type (size_t)
++foo - is a value (now 3) of type (int)

None of these have 'object' context as I see it. What are you trying to
tell us here?

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #41
Joe Wright <jw*****@comcast.net> writes:
Chris Torek wrote:

[ snip ]
Once you understand the idea of "object context" and "value context",
you simply have to memorize which operators have which context(s):
&foo - object context
sizeof foo - object (or maybe even "sizeof") context
foo + bar - two value contexts
foo = bar - one object context, one value context
++foo - object context
and so on.

I know you Chris and I love you like a brother but given..
int foo = 2, bar = 3;

&foo - is the address of foo, a 'value' of type (int*)
sizeof foo - is a value (4 at my house) of type (size_t)
++foo - is a value (now 3) of type (int)

None of these have 'object' context as I see it. What are you trying
to tell us here?


In "&foo", he's talking about the context in which the name "foo"
appears, not the entire expression. The argument to the unary "&"
operator must be an lvalue, so foo is in an "object context". Similarly,
the argument of unary "++" must be an lvalue.

He's mistaken about sizeof, which doesn't require an lvalue.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #42

Keith Thompson wrote:
ju**********@yahoo.co.in writes:
[...
I always have a confusion that why array is called "non modifiable
lvalue", because we can always modify the contents of an array. The
only reason that arr1 = NULL; should not be allowed because arr1 is
an array object and RHS is not compatible with it. That might be the
reason, standard doesn't allow modifying array object in this manner
and to prevent this made it non modifiable lvalue.


An array isn't (necessarily) a non-modifiable lvalue.

C99 6.3.2.1p3 says:

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. If the array
object has register storage class, the behavior is undefined.

In
arr1 = NULL;
(assuming arr1 is the name of an array object), arr1 doesn't match any
of the exceptions above, so it's converted to a pointer to the initial
element of arr1 -- and this pointer value is explicitly not an lvalue.


That means arr1 can never be used as an lvalue. The moment the operator
sizeof or & is applied on to it, it becomes an rvalue.
But the question is why such a limitation ?
Why not the following is allowed ?

int arr1[3];
arr1 = {1,2,3};

Nov 15 '05 #43
ju**********@yahoo.co.in writes:
Keith Thompson wrote:
In
arr1 = NULL;
(assuming arr1 is the name of an array object), arr1 doesn't match any
of the exceptions above, so it's converted to a pointer to the initial
element of arr1 -- and this pointer value is explicitly not an lvalue.


That means arr1 can never be used as an lvalue. The moment the operator
sizeof or & is applied on to it, it becomes an rvalue.
But the question is why such a limitation ?
Why not the following is allowed ?

int arr1[3];
arr1 = {1,2,3};


Allowing that kind of thing would drastically change the language and
break existing code.

For example, if it were legal to assign array values, it should also
be legal to pass array values as function arguments. This would
change the meaning of
printf("hello, world\n");
so it would pass an array value, not a pointer value, to printf().
Either that, or we'd have to treat arrays differently in different
contexts.

There are languages that support array value in ways that C doesn't,
so it's not inherently a bad idea; it's just not the way C does
things, and it's a few decades too late to change it.

Conceivably the language could be changed to allow array values only
in contexts that are currently illegal, but I don't think the result
would be coherent.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #44
Keith Thompson <ks***@mib.org> writes:
ju**********@yahoo.co.in writes:
[...
I always have a confusion that why array is called "non modifiable
lvalue", because we can always modify the contents of an array. The
only reason that arr1 = NULL; should not be allowed because arr1 is
an array object and RHS is not compatible with it. That might be the
reason, standard doesn't allow modifying array object in this manner
and to prevent this made it non modifiable lvalue.

A modifiable lvalue is an expression that is used directly
to write-access an object, namely with increment/decrement
or assignment operators. Arrays (or any expression with
array type) are never used directly in this way, but only
indirectly after being converted to a pointer and then
dereferenced or indexed. An array object is a "modifiable"
object; an array expression is not a modifiable lvalue.

Arrays need to be lvalues only so they can be used as
operands of the address-of operator. The address-of
operator needs only an lvalue for its operand, not a
modifiable lvalue. Hence arrays don't need to be modifiable
lvalues.

(Please note the response above is to what junky_fellow
wrote.)

An array isn't (necessarily) a non-modifiable lvalue.


An array is never a modifiable lvalue; 6.3.2.1 p1.
Nov 15 '05 #45
Tim Rentsch wrote:

Keith Thompson <ks***@mib.org> writes:

An array isn't (necessarily) a non-modifiable lvalue.


An array is never a modifiable lvalue; 6.3.2.1 p1.


"A modifiable lvalue is an lvalue that does not have array type, "

--
pete
Nov 15 '05 #46
pete <pf*****@mindspring.com> writes:
Tim Rentsch wrote:

Keith Thompson <ks***@mib.org> writes:

> An array isn't (necessarily) a non-modifiable lvalue.


An array is never a modifiable lvalue; 6.3.2.1 p1.


"A modifiable lvalue is an lvalue that does not have array type, "


Right. The comma is critical; there are more criteria. (I mention
that because I mis-read it the first time.)

(I added the "(necessarily)" because I was too lazy to think it
through and/or look it up. It wasn't meant to imply that an array can
sometimes be a modifiable lvalue, though I see that it could be read
that way.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #47
Keith Thompson <ks***@mib.org> writes:
pete <pf*****@mindspring.com> writes:
Tim Rentsch wrote:

Keith Thompson <ks***@mib.org> writes:

> An array isn't (necessarily) a non-modifiable lvalue.

An array is never a modifiable lvalue; 6.3.2.1 p1.


"A modifiable lvalue is an lvalue that does not have array type, "


Right. The comma is critical; there are more criteria. (I mention
that because I mis-read it the first time.)

(I added the "(necessarily)" because I was too lazy to think it
through and/or look it up. It wasn't meant to imply that an array can
sometimes be a modifiable lvalue, though I see that it could be read
that way.)


Ah, now I see what you meant: an array wouldn't *have* to
be a non-modifiable lvalue. I believe that statement is
correct; the standard could have been written so array
expressions were modifiable lvalues, and nothing would
change, because in every place where it might be relevant
the array expression would be converted to a pointer, and so
would be illegal anyway. Probably 6.3.2.1 p1 excludes array
expressions from being modifiable lvalues so as to make it
absolutely clear that arrays can't be used with =, ++, etc.
Nov 15 '05 #48
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
pete <pf*****@mindspring.com> writes:
> Tim Rentsch wrote:
>>
>> Keith Thompson <ks***@mib.org> writes:
>
>> > An array isn't (necessarily) a non-modifiable lvalue.
>>
>> An array is never a modifiable lvalue; 6.3.2.1 p1.
>
> "A modifiable lvalue is an lvalue that does not have array type, "


Right. The comma is critical; there are more criteria. (I mention
that because I mis-read it the first time.)

(I added the "(necessarily)" because I was too lazy to think it
through and/or look it up. It wasn't meant to imply that an array can
sometimes be a modifiable lvalue, though I see that it could be read
that way.)


Ah, now I see what you meant: an array wouldn't *have* to
be a non-modifiable lvalue. I believe that statement is
correct; the standard could have been written so array
expressions were modifiable lvalues, and nothing would
change, because in every place where it might be relevant
the array expression would be converted to a pointer, and so
would be illegal anyway. Probably 6.3.2.1 p1 excludes array
expressions from being modifiable lvalues so as to make it
absolutely clear that arrays can't be used with =, ++, etc.


I'm glad you were able to read into what I wrote something cleverer
than what I intended. In fact, I was just being lazy. If I had spent
a minute or two doing more research, I could have dropped the
"(necessarily)"; I didn't bother because it didn't seem relevant to my
point. I should have realized that irrelevance doesn't prevent long
threads. 8-)}

Yes, I suppose the "does not have array type" phrase in 6.3.2.1p1 is,
strictly speaking, redundant, but it's a *good* redundancy. Without
it, if arr is an array object, then the name "arr" in "sizeof arr" or
"&arr" would be a modifiable lvalue, but it wouldn't matter because
neither operator modifies its argument. But I think the wording is
cleaner as it is.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #49
The output for the three elements are
ello
ello
ello

while in the code if i go with str++
the o/p is

ello
Hello
Hello

Please clarify

Thanks

Pradyut
http://pradyut.tk
http://spaces.msn.com/members/oop-edge/
http://groups-beta.google.com/group/oop_programming
India

pete wrote:
ju**********@yahoo.co.in wrote:

char *str1 = "Hello";
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

Is it legal to modify str1, arr1 and arr2 ?


Depends on what you mean.

/* BEGIN new.c */

#include <stdio.h>
#include <string.h>

int main(void)
{
char *str1 = "Hello";
char arr1[] = { "Hello" };
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };

strcpy(arr1, ++str1);
strcpy(arr2, arr1);
puts(str1);
puts(arr1);
puts(arr2);
return 0;
}

/* END new.c */
--
pete


Nov 15 '05 #50

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

16 posts views Thread by Don Starr | last post: by
7 posts views Thread by al | last post: by
17 posts views Thread by Janice | last post: by
8 posts views Thread by junky_fellow | last post: by
6 posts views Thread by copx | last post: by
41 posts views Thread by Dead Loop | last post: by
8 posts views Thread by arnuld | last post: by
4 posts views Thread by =?ISO-8859-15?Q?Jean=2DFran=E7ois?= Lemaire | last post: by
5 posts views Thread by polas | last post: by
7 posts views Thread by lithiumcat | last post: by
1 post views Thread by Waqarahmed | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.