Assigning values to char arrays

E

emyl

Hi all,

here's an elementary question. Assume I have declared two variables,

char *a, **b;

I can then give a value to a like

a="hello world";

The question is, how should I assign values to b? A simple

b[0]="string";

results in a segmentation fault.

Answers greatly appreciated.

Regards, Emyl.
 
R

Richard

emyl said:
Hi all,

here's an elementary question. Assume I have declared two variables,

char *a, **b;

b is a pointer to a char pointer.
I can then give a value to a like

a="hello world";

The question is, how should I assign values to b? A simple

b[0]="string";

*b = "s";
 
R

Richard Heathfield

emyl said:
Hi all,

here's an elementary question. Assume I have declared two variables,

char *a, **b;

I can then give a value to a like

a="hello world";

The question is, how should I assign values to b? A simple

b[0]="string";

results in a segmentation fault.

Answers greatly appreciated.

Your definition:

char *a, **b;

reserves sufficient storage for a pointer-to-char named a, and a
pointer-to-pointer-to-char named b.

a="hello world";

assigns a value to this pointer-to-char, the value in question being the
address of the first character in the given string literal.

But b[0]="string"; is a problem, not because there's anything wrong with
the syntax, but because you've made an incorrect assumption.

b is a pointer-to-pointer-to-char, but you haven't pointed it to any
pointers-to-char, so it is currently indeterminate. b[0]="string"; is
*not* an attempt to give a value to b. It is an attempt to give a value to
b[0]. But b[0] is meaningless unless b has a meaningful value.

You can give b a meaningful value in any of several ways, but the most
obvious is to allocate some fresh memory for it:

#include <stdlib.h>

/* allocate memory for some pointers-to-char */
char **cpalloc(size_t n)
{
char **ptr = malloc(n * sizeof *ptr);
if(ptr != NULL)
{
while(n--)
{
ptr[n] = NULL;
}
}
return ptr;
}

#include <stdio.h>

int main(void)
{
char *a, **b;
a = "what has it got in its pocketses?";
b = cpalloc(2);
if(b != NULL)
{
b[0] = "string";
b[1] = "nothing";

printf("%s\n", a);
printf("%s or %s\n", b[0], b[1]);

free(b);
}
return 0;
}

Be careful. The cpalloc function written above does not allocate storage
for strings, only for a collection of pointers to char. A pointer to char
is sufficient for pointing at a string, but not for storing it.
 
C

CBFalconer

emyl said:
here's an elementary question. Assume I have declared two variables,
char *a, **b;
I can then give a value to a like
a="hello world";
The question is, how should I assign values to b? A simple
b[0]="string";
results in a segmentation fault.

"char **b;" declares a pointer to a pointer to char. You could
initialize it with "b = &a;" (provided the a declaration is
present). Then **b is a[0].

However note that your initialization of <a = "hello world";>
leaves a pointing to an unmodifiable string.
 
R

Richard

Richard said:
emyl said:
Hi all,

here's an elementary question. Assume I have declared two variables,

char *a, **b;

b is a pointer to a char pointer.
I can then give a value to a like

a="hello world";

The question is, how should I assign values to b? A simple

b[0]="string";

*b = "s";

*slaps cold water on face*

Sorry. That was bullshit. I thought I had included the initialisation
line. See other replies.

Scary.
 
E

emyl

BIG sigh of relief... Thanks all for your replies. More
specifically,

Richard: Your suggestion is one of the bazillion things I had tried
more or less a
t random. Like you noticed, it won't work. Thanks for taking the
time to answer.

Richard H.: My heartfelt thanks for a crystal clear answer that works
like a charm a
nd is general enough to use it in the broader context of my project.
If I could I'd buy
a beer to you and candy to your kids..............

Chuck F.: Thanks a lot for your answer. Of all the simple
possibilities it was the
only one I didn't try, and I guess the only correct one. If I had
thought of that
I'd have had enough of a clue to solve the problem.
 
S

somenath

emyl said:




here's an elementary question. Assume I have declared two variables,
char *a, **b;
I can then give a value to a like
a="hello world";
The question is, how should I assign values to b? A simple
b[0]="string";

results in a segmentation fault.
Answers greatly appreciated.

Your definition:

char *a, **b;

reserves sufficient storage for a pointer-to-char named a, and a
pointer-to-pointer-to-char named b.

a="hello world";

assigns a value to this pointer-to-char, the value in question being the
address of the first character in the given string literal.

But b[0]="string"; is a problem, not because there's anything wrong with
the syntax, but because you've made an incorrect assumption.

b is a pointer-to-pointer-to-char, but you haven't pointed it to any
pointers-to-char, so it is currently indeterminate. b[0]="string"; is
*not* an attempt to give a value to b. It is an attempt to give a value to
b[0]. But b[0] is meaningless unless b has a meaningful value.

You can give b a meaningful value in any of several ways, but the most
obvious is to allocate some fresh memory for it:

#include <stdlib.h>

/* allocate memory for some pointers-to-char */
char **cpalloc(size_t n)
{
char **ptr = malloc(n * sizeof *ptr);
if(ptr != NULL)
{
while(n--)
{
ptr[n] = NULL;
}
}
I have one question . Can memset be used as
memset(ptr,0,n);
Instead of the while loop ?
 
R

Richard Heathfield

somenath said:
char **ptr = malloc(n * sizeof *ptr);
if(ptr != NULL)
{
while(n--)
{
ptr[n] = NULL;
}
}
I have one question . Can memset be used as
memset(ptr,0,n);
Instead of the while loop ?

Not unless you can guarantee that the representation of null pointers on
all target platforms is all-bits-zero. I don't recall that the OP
mentioned any platforms. The code I supplied was portable to any hosted
implementation.

In situations where you /can/ use memset, don't bother - just calloc it
instead.
 
S

somenath

somenath said:
char **ptr = malloc(n * sizeof *ptr);
if(ptr != NULL)
{
while(n--)
{
ptr[n] = NULL;
}
}
I have one question . Can memset be used as
memset(ptr,0,n);
Instead of the while loop ?

Not unless you can guarantee that the representation of null pointers on
all target platforms is all-bits-zero. I don't recall that the OP
mentioned any platforms. The code I supplied was portable to any hosted
implementation.

In situations where you /can/ use memset, don't bother - just calloc it
instead.

Many thanks for the response.

But my understanding was in pointer context 0 and NULL is converted to
null pointer. And converting to null pointer is compiler
responsibility. So I thought 0 in memset will be converted to null
pointer (which is system specific).

I would request you to correct me as I am feeling I may be
misunderstood some concept.
 
R

Richard Heathfield

somenath said:

But my understanding was in pointer context 0 and NULL is converted to
null pointer. And converting to null pointer is compiler
responsibility. So I thought 0 in memset will be converted to null
pointer (which is system specific).

I would request you to correct me as I am feeling I may be
misunderstood some concept.

You need to separate two very different ideas - *value* and
*representation*. You are quite right that an assignment such as:

char *p;

p = 0; /* ...this... */

requires the compiler to assign p a null pointer value. Let's just assume
for the sake of argument that we're on a platform where a null pointer is
*not* all-bits-zero. In this circumstance, the compiler is obliged to do
any necessary magic to ensure that p ends up with a null pointer value as
a result of the assignment.

But memset is a very different thing indeed. It takes no account whatsoever
of value, and it doesn't know that what you've passed to it is the address
of the first of a bunch of pointers. All it knows is that it has to set a
bunch of bytes to such-and-such, starting at such-and-such an address and
continuing for so-many bytes. It cares about the value you pass only
insofar as it can be represented as an unsigned char, and it doesn't care
a jot about the value of the resulting object.

The memset function can be (isn't!, but can legally be) implemented like
this:

#include <stddef.h>
void *memset(void *s, int c, size_t n)
{
unsigned char *p = s;
while(n--)
{
*p++ = c;
}
return s;
}

As you can see, memset doesn't (and indeed can't) care what kind of
object's bytes it is hacking at, and so it can't distinguish between a
pointer value and some other kind of value. Thus, in the original code,
memset(&ptr[0], 0, n * sizeof *ptr); would merely have set the object
representation to all-bits-zero, without any attempt whatsoever to address
the question of which value the object would have afterwards.
 
A

Ark Khasin

Richard Heathfield wrote:
The memset function can be (isn't!, but can legally be) implemented like
this:

#include <stddef.h>
void *memset(void *s, int c, size_t n)
{
unsigned char *p = s;
while(n--)
{
*p++ = c;
}
return s;
}
would merely have set the object
representation to all-bits-zero, without any attempt whatsoever to address
the question of which value the object would have afterwards.
As a practitioner, I didn't think twice to clear all bits with memset
clones including the likes of the code above. But now this post scared
me: if unsigned char has padding bits in its representation (which I
guess is allowed) then what do I get?
unsigned a;
memset_as_above(&a, 0, sizeof(a));
Will a necessarily compare equal to 0?
 
R

Richard

Ark Khasin said:
Richard Heathfield wrote:


As a practitioner, I didn't think twice to clear all bits with memset
clones including the likes of the code above. But now this post scared
me: if unsigned char has padding bits in its representation (which I

Scarey isn't it. The explanations given here confuse the newbie no end
because they include the instances of extinct system and a tiny minority
of systems which feature all sorts of hocus pocus. You know "a NULL
pointer is not necessarily all bit 0s" for example.....

or

p=0; /* p is not necessarily equal to zero */
 
B

Ben Bacarisse

Ark Khasin said:
Richard Heathfield wrote:


As a practitioner, I didn't think twice to clear all bits with memset
clones including the likes of the code above. But now this post scared
me: if unsigned char has padding bits in its representation (which I
guess is allowed)

No. unsigned char may not have padding bits. All the bits must be value
bits.
then what do I get?
unsigned a;
memset_as_above(&a, 0, sizeof(a));
Will a necessarily compare equal to 0?

Yes. 6.2.6.2p5 says (in part):

"... For any integer type, the object representation where all the
bits are zero shall be a representation of the value zero in that
type."

This is marked with change bars in recent PDFs so I suspect it is the
result of a clarification. But of what? Unsigned integer values are
represented with two sets of bits: values bits and padding bits. On a
machine with no padding bits, the above produces a value of 0. On one
with padding bits there are two possibilities. if there are no trap
representations (the padding bits are just that -- pure padding) then,
again a value of zero is guaranteed. Only on a machine with some trap
representations could the above code not produce a value of zero. It
is very unlikely that all bits zero would be a trap rep. (the only one
I have ever seen uses a parity bit) and it seems the committee has
clarified that this daft case is to be ruled out.

RH's point was something else altogether -- that all bits zero is not
guaranteed to produce a null pointer (to be scrupulously correct, it
is not guaranteed to produce a value that compares equal to a null
pointer constant). I.e.

void *a;;
memset_as_above(&a, 0, sizeof a);
if (a == 0) {
/* not guaranteed */
}

I would not be seriously concerned about code that makes this
assumption, but one can always test it at run time to be sure. On my
personal nervousness scale, this one is very low down.
 
B

Ben Bacarisse

Richard said:
Scarey isn't it. The explanations given here confuse the newbie no end
because they include the instances of extinct system and a tiny minority
of systems which feature all sorts of hocus pocus. You know "a NULL
pointer is not necessarily all bit 0s" for example.....

Beginners can, and should, skip those post they find confusing. We
can't restrict posting to those that can't be misunderstood by some
learners. Personally (having lived though the days of peculiar
hardware) I am more worried a bout *future* systems than obsolete
ones.
p=0; /* p is not necessarily equal to zero */

Who is suggesting this? What do you mean by it? If you are trying to
avoid confusing beginners, do you think the above helps to keep things
clear?
 
A

Ark Khasin

Ben said:
No. unsigned char may not have padding bits. All the bits must be value
bits.
Why?
6.2.6.2 says "For unsigned integer types other than unsigned char, the
bits of the object representation shall be divided into two groups:
value bits and padding bits (there need not be any of the latter).
But I couldn't find anything saying that unsigned char *may not* have
padding bits.
Yes. 6.2.6.2p5 says (in part):

"... For any integer type, the object representation where all the
bits are zero shall be a representation of the value zero in that
type."

This is marked with change bars in recent PDFs so I suspect it is the
result of a clarification. But of what? Unsigned integer values are
represented with two sets of bits: values bits and padding bits. On a
machine with no padding bits, the above produces a value of 0. On one
with padding bits there are two possibilities. if there are no trap
representations (the padding bits are just that -- pure padding) then,
again a value of zero is guaranteed.
Agreed - if indeed unsigned char must have no padding
Only on a machine with some trap
representations could the above code not produce a value of zero. It
is very unlikely that all bits zero would be a trap rep. (the only one
I have ever seen uses a parity bit) and it seems the committee has
clarified that this daft case is to be ruled out.

RH's point was something else altogether
That's why my a propos question was with the subject changed
-- that all bits zero is not
guaranteed to produce a null pointer (to be scrupulously correct, it
is not guaranteed to produce a value that compares equal to a null
pointer constant).
That's where I am lost and reading the standard doesn't help:
What's the difference between a value of an object and how it compares
equal? I mean, if a==b, whatever their representations, in what
context(s) does it make sense to say they may have different values?
[NEGATIVE_ZERO comes to mind - and goes away. BTW, is it fair to say
that bitwise logic is a magic performed on representations, and not on
values?]

I.e.
void *a;;
memset_as_above(&a, 0, sizeof a);
if (a == 0) {
/* not guaranteed */
//Which is correct but implies
{
void **pNULL = 0;
if(a==*pNULL) {
/* not guaranteed */
}
} //Weird!..
 
A

Ark Khasin

Richard said:
Scarey isn't it. The explanations given here confuse the newbie no end
because they include the instances of extinct system and a tiny minority
of systems which feature all sorts of hocus pocus. You know "a NULL
pointer is not necessarily all bit 0s" for example.....

or

p=0; /* p is not necessarily equal to zero */
I am not to argue who of us two is more of a newbie, but your post sheds
no light on the question asked. Ego bubbling?
 
R

Richard

Ark Khasin said:
I am not to argue who of us two is more of a newbie, but your post
sheds no light on the question asked. Ego bubbling?

More sharing your "scared" comment. It's easy to forget to think these
things out and these are things that some C programmer go their entire
lives without realising exist.
 
S

santosh

Ark said:
Ben Bacarisse wrote:
Why?
6.2.6.2 says "For unsigned integer types other than unsigned char, the
bits of the object representation shall be divided into two groups:
value bits and padding bits (there need not be any of the latter).
But I couldn't find anything saying that unsigned char *may not* have
padding bits.

Well the above quote says that unsigned char may not have _both_ padding
and value bits. Obviously the bit type left out has to be padding
bits - otherwise one would not be able to potably use unsigned char
objects.

<snip>
 
A

Ark Khasin

santosh said:
Well the above quote says that unsigned char may not have _both_ padding
and value bits. Obviously the bit type left out has to be padding
bits - otherwise one would not be able to potably use unsigned char
objects.
Is this "just a theory"? IMHO, 6.2.6.2 says *exactly nothing* about
unsigned char.
 

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,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top