Change the second element of char array

Z

zloy tapok

Hello guys,

Here is the test code which is segfaulted:

cat ptr.c
#include <stdio.h>

int main()
{
char *ch = "abc";

ch++;
*ch = "A";
printf("%c", *ch);

return 0;
}

The question is: why I cannot write the "A" character instead of "b"?
 
S

Siri Cruz

zloy tapok said:
Hello guys,

Here is the test code which is segfaulted:

cat ptr.c
#include <stdio.h>

int main()
{
char *ch = "abc";

ch++;
*ch = "A";
printf("%c", *ch);

return 0;
}

The question is: why I cannot write the "A" character instead of "b"?

Because c is made to point to the memory containing the constant string, and on
most modern implementations with page mapped addressing that particular memory
will be read only.

gcc, at least, has an option to put constant strings in read/write memory, and
some cheaper hardware doesn't have address protection.


char *c1 = "abc";
char *c2 = "abc";
char c3[] = "abc";
char *c = c3;

In this case c3 is allocated at least four chars in read/write memory
initialised to 'a', 'b', 'c', and 0, then c is made to point to this read/write
memory. The memory pointed to by c1 and c will be different. The memory pointed
to be c1 and c2 might be different or the same, depending on the compiler; in
either case c1 and c2 should be treated as read only.
 
J

James Kuyper

Hello guys,

Here is the test code which is segfaulted:

cat ptr.c
#include <stdio.h>

int main()
{
char *ch = "abc";

ch++;
*ch = "A";
printf("%c", *ch);

return 0;
}

The question is: why I cannot write the "A" character instead of "b"?

During translation phase 7, the characters that make up a string literal
are used to initialize an array. "If the program attempts to modify such
an array, the behavior is undefined." (6.4.5p7). It's not uncommon for
an implementation of C to place such arrays in read-only memory, which
would explain your problem.

If you want to have an modifiable array of char, you have to define one:

char alphabet[] = "abc";

There is still nominally an unnamed array containing 'a', 'b', 'c' , and
'\0' that cannot be safely modified - but the array named 'alphabet' has
a copy of that string, and can be modified:

alphabet[1] = 'A';
 
G

glen herrmannsfeldt

(snip)
If you want to have an modifiable array of char, you have to define one:
char alphabet[] = "abc";
There is still nominally an unnamed array containing 'a', 'b', 'c' , and
'\0' that cannot be safely modified - but the array named 'alphabet' has
a copy of that string, and can be modified:
alphabet[1] = 'A';

In that case, you have an auto array initialized to the specified value
each time it is created. You can also:

static char alphabet[] = "abc";

Where it is only initialized once.

-- glen
 
D

Dustin Boyd

You're not using the correct quotation marks for one thing. An integer character literal should be in single quotation marks:

*ch = 'A';

Aside from that, everybody else is correct. "abc" is an immutable string by default on many platforms, so trying to modify something that isn't supposed to be modified can result in a segfault.
 
K

Keith Thompson

zloy tapok said:
Here is the test code which is segfaulted:

cat ptr.c
#include <stdio.h>

int main()
{
char *ch = "abc";

ch++;
*ch = "A";
printf("%c", *ch);

return 0;
}

The question is: why I cannot write the "A" character instead of "b"?

The comp.lang.c FAQ is at <http://www.c-faq.com/>.

You've just asked question 1.32.
 
K

Kaz Kylheku

Hello guys,

Here is the test code which is segfaulted:

This exact topic (programs crashing when assigning to the element of a string
literal) was discussed at length very recently in this very newsgroup (mere
days ago), not to mention numerous times over the past twenty years or more.

I believe it is addressed in the comp.lang.c FAQ also.
 
E

Eric Sosman

Hello guys,

Here is the test code which is segfaulted:

cat ptr.c
#include <stdio.h>

int main()
{
char *ch = "abc";

ch++;
*ch = "A";

The compiler should have produced a diagnostic message
for this line, because the things on the left and right of
the assignment have incompatible types:

- Since `ch' is a "pointer to char," `*ch' is a char.
Whatever you attempt to store in `*ch' must therefore
be convertible to a char.

- However, "A" is a string literal. In this context,
it denotes an array of two char elements, the first
being an 'A' and the second a '\0'. And in this
context (as in most), mentioning an array yields a
pointer to the array's first element. So, the thing
on the right is a value of type `char*'.

So: On the left, a reference to someplace that can store
values of type `char'. On the right, a value of type `char*',
which is not at all the same thing. The compiler is required
to complain. After complaining, it can reject the program or
"make corrections and carry on" -- but what corrections it might
have made, and how it carries on, are not specified by C. If
the program runs, it might do anything at all.
 
M

Malcolm McLean

Holy cow. A new record for stringing out the obvious in such a manner as
to totally confuse an obvious noob. I salute you.
const was added to the language at a later date.

so char *str = "Fred"; is legal, even though "Fred" is read-only. The compiler should enforce
const char *str = "Fred";
to be consistent, but that would break lots of code.

You can't expect someone new to C to know that.
 
K

Kaz Kylheku

So has just about every single Q posed here.

Whereas that is true with regard to the second part ("numerous times over
twenty years or more") it is not true with regard to the first, since not every
Q has been discussed at length mere days ago.
 
C

Charles Richmond

Siri Cruz said:
Because c is made to point to the memory containing the constant string,
and on
most modern implementations with page mapped addressing that particular
memory
will be read only.

First, if you want to assign the second postion to be the letter A, you say:

*ch = 'A';

and *not*

*ch = "A";

When a letter or group of letters is inclosed in double quote marks, it
represents the *address* of where this string constant is stored in memory.
A letter in single quote marks is a *character* constant. Characters are
treated like small integers (sometimes unsigned) and can be used like an
integer. So you can write:

int x;

x = 'A' + 15;


Second... you are trying to change a string *constant*, the address of which
you put in the pointer "ch". It is *illegal* to change a string constant.
Some (many???) C compilers keep only *one* copy of each C string constant.
For code compiled with such a compiler, any time you declare: char *xyzzy
= "abc"; you will get the *same* address stored in the variable, in this
case "xyzzy". If the compiler keeps only one copy of the string constant
"abc", then *anytime* you use the constant "abc", you will get the address
of that one and only copy of that string constant.

You can declare:

char ch[] = "abc";

In this case, you will be initializing the *array* "ch" to contain the value
"abc\0". (The compiler will add the null byte at the end for you.)

If you *must* increment a pointer for some reason, declare:

char ch[] = "abc";
char *chptr = ch;

Now the pointer "chptr" points to the array "ch", and *not* a constant
string. So you can say:

chptr++;
*chptr = 'A';

printf("%s\n",ch);
 
K

Keith Thompson

Charles Richmond said:
First, if you want to assign the second postion to be the letter A, you say:

*ch = 'A';

and *not*

*ch = "A";

Correct (and I think it's already been mentioned).
When a letter or group of letters is inclosed in double quote marks, it
represents the *address* of where this string constant is stored in
memory.

Actually a string literal of length N has type char[N+1], i.e., array of
N+1 chars (the +1 is for the terminating '\0'). It's implicitly
converted to a pointer to the array's first element in most, but not
all, contexts. Most obviously, sizeof "abcd" yields 5, the size of the
array, not the size of a pointer.
A letter in single quote marks is a *character* constant. Characters are
treated like small integers (sometimes unsigned) and can be used like an
integer. So you can write:

int x;

x = 'A' + 15;

Character constants are of type int. The type char may be either a
signed type or an unsigned type. Yes, it would make more sense for
character constants to be of type char, but it rarely matters, since in
an assignment like:

char c;
c = 'A';

the int value of 'A' is implicitly converted to char.
Second... you are trying to change a string *constant*, the address of which
you put in the pointer "ch". It is *illegal* to change a string constant.
Some (many???) C compilers keep only *one* copy of each C string constant.
For code compiled with such a compiler, any time you declare: char *xyzzy
= "abc"; you will get the *same* address stored in the variable, in this
case "xyzzy". If the compiler keeps only one copy of the string constant
"abc", then *anytime* you use the constant "abc", you will get the address
of that one and only copy of that string constant.

The C standard doesn't actually use the term "illegal", at least not in
that way. Attempting to modify a string literal has undefined behavior.
This isn't just about sharing memory for identical or overlapping
strings. Most compilers these days store string literals in read-only
memory (not hardware ROM, but memory protected from modification by the
OS), resulting in a program crash if you try to modify it.

[snip]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top