2D-array of pointers, set all to null?

W

WP

Hello, is there something neat in the c++ standard library that can help
me set all elements of a two-dimensional array of pointers to NULL? Like
fill_n(), maybe? Right now, I'm using two for loops (one nested) and
wanted to know what alternatives there are. My compiler ships with a
preliminary TR1-implementation.
Another thing I need to do is to call delete on the pointers in the
array at some other point in the program, am I stuck with the two for
loops there?

- Eric
 
J

Juha Nieminen

WP said:
Hello, is there something neat in the c++ standard library that can help
me set all elements of a two-dimensional array of pointers to NULL? Like
fill_n(), maybe? Right now, I'm using two for loops (one nested) and
wanted to know what alternatives there are. My compiler ships with a
preliminary TR1-implementation.
Another thing I need to do is to call delete on the pointers in the
array at some other point in the program, am I stuck with the two for
loops there?

Well, you could do it with a single memset() call, but I'm not
absolutely sure how portable that is (although I believe it's portable
*in practice*).
 
J

James Kanze

Well, you could do it with a single memset() call, but I'm not
absolutely sure how portable that is (although I believe it's
portable *in practice*).

You can't set pointers to null with memset. And it's not
portable in practice (although it will work on a few widely used
systems).
 
J

Juha Nieminen

James said:
You can't set pointers to null with memset. And it's not
portable in practice (although it will work on a few widely used
systems).

Could you mention, as an example, a system for which a C++ compiler is
available and where a pointer cannot be nulled with memset?
 
G

Gennaro Prota

James said:
You can't set pointers to null with memset. And it's not
portable in practice (although it will work on a few widely used
systems).

Right :) However using an empty initializer list in the OP case
should be fine, as the pointer elements get zero-initialized. This
wasn't clearly specified but has always been the intent:

<http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#277>

So, unless your compiler vendor fails to know the intent... :)
 
J

James Kanze

Could you mention, as an example, a system for which a C++
compiler is available and where a pointer cannot be nulled
with memset?

I think you've got that a little backwards. I don't know every
system around, and neither do you. So on what basic do you say
that it will work in practice? On a guarantee in the standard?
On some set of "reasonable assumptions" about what an
implementation can or might do? Or on what?
 
J

Joe Greer

Hello, is there something neat in the c++ standard library that can help
me set all elements of a two-dimensional array of pointers to NULL? Like
fill_n(), maybe? Right now, I'm using two for loops (one nested) and
wanted to know what alternatives there are. My compiler ships with a
preliminary TR1-implementation.
Another thing I need to do is to call delete on the pointers in the
array at some other point in the program, am I stuck with the two for
loops there?

- Eric

The standard certainly implies that you can treat:

char * arr[X][Y]

as

char * arr[X*Y]

so...

something like:

std::fill(reinterpret_cast<char **>(arr),
reinterpret_cast<char **>(arr) + X*Y, 0);

Should work. It seems awfully obfuscated to me though. I would probably
just keep it as 2 loops and be done with it, or if you have more than one
place you do this, a small function might be in order. Then it would be:

nullarr(arr);

or some such. You could even templatize it ot make it generic for all 2D
array uses.

joe
 
J

Juha Nieminen

James said:
I think you've got that a little backwards. I don't know every
system around, and neither do you. So on what basic do you say
that it will work in practice? On a guarantee in the standard?
On some set of "reasonable assumptions" about what an
implementation can or might do? Or on what?

The standard doesn't guarantee a lot of things, yet it may still be
reasonable to expect them anyways. For example, the standard doesn't
guarantee that argv[0] actually contains something. However, it's still
reasonable, in *practical* systems, to expect something to be there.
 
J

James Kanze

The standard doesn't guarantee a lot of things, yet it may
still be reasonable to expect them anyways. For example, the
standard doesn't guarantee that argv[0] actually contains
something. However, it's still reasonable, in *practical*
systems, to expect something to be there.

The standard actually does guarantee "something" in argv[0],
just not what you might want. And of course, if you want to use
it in portable code, you have to jump through some hoops, not
because of the standard, but in this case, because almost no
implementation is really conform.

In fact, what you can count on in argv[0] is what you've gotten,
historically. And historically, memset didn't work for nulling
pointers, so you can't argue historical tradition for it.

My point is: if you want some (more or less) guarantee beyond
what the standard gives, you need to base it on some reason.
The fact that it works on a couple of widespread implementations
is not sufficient. Given the number of implementations I've
seen and heard of, if I'd never heard of an implementation where
it didn't work, I'd perhaps consider it (although I'm not sure);
given that I've actually heard of implementations where it
didn't work, obviously, you can't use that reason, regardless of
whether it is acceptable. (An example of where I would accept
that reason:

std::vector< char > v ;
int ch = std::cin.get() ;
while ( ch != EOF && ch != '\n' ) {
v.push_back( ch ) ;
}

Implementation defined, according to the standard, and the C
standard even explicitly mentions the possibility of an
implementation defined signal. However, given that no
implementation has, to my knowledge, made it fail *AND* given
that this is just a rewrite of the basic way K&R said to do
character input, back in the first edition of the C book, and
that the idiom is enormously widespread, among extremely
competent people, I think it's probably safe to say that no
implementation would dare break it. But there are a lot of
conditions involved.

You could raise the argument that using memset to set pointers
to null is widespread, and thus, implementations won't dare to
break it. Except that they have in the past, so apparently, it
wasn't widespread enough. And it's a very valid implementation
technique on some architectures. (Come to think of it, I rather
doubt that it would work on a Unisys MCP. There's a tag bit in
their words, and I sort of think that it has to be 1 if the word
is a pointer.)
 
J

James Kanze

@mid.individual.net:
The standard certainly implies that you can treat:
char * arr[X][Y]

char * arr[X*Y]

Where? I know that when the original C standard was being
drafted, great care was taken to allow "fat" bounds checking
pointers, and that every time there was a doubt, the C committee
has clarified that they meant what they said. Your suggestion
is undefined behavior. (In practice, of course, I can't imagine
an effective implementation where it didn't work.)
 
J

Juha Nieminen

James said:
The standard actually does guarantee "something" in argv[0],
just not what you might want.

No. The standard actually allows argc to be 0, in which case argv[0]
will be a null pointer (as per the standard).
Even if argc > 0, the standard still allows argv[0] to be an empty string.
But how many CLI programs have you seen that actually check that
argc>0 and that argv[0] actually contains something else than an empty
string before referring to argv[0] (eg. to print the command-line
syntax)? :p

(Ok, I have to admit I got this information from the freely-available
C++ standard draft. I would be surprised if the official standard said
something different, though.)
 
G

Gennaro Prota

Joe said:
Hello, is there something neat in the c++ standard library that can help
me set all elements of a two-dimensional array of pointers to NULL? Like
fill_n(), maybe? Right now, I'm using two for loops (one nested) and
wanted to know what alternatives there are. My compiler ships with a
preliminary TR1-implementation.
Another thing I need to do is to call delete on the pointers in the
array at some other point in the program, am I stuck with the two for
loops there?

- Eric

The standard certainly implies that you can treat:

char * arr[X][Y]

as

char * arr[X*Y]

so...

something like:

std::fill(reinterpret_cast<char **>(arr),
reinterpret_cast<char **>(arr) + X*Y, 0);

Should work. It seems awfully obfuscated to me though. I would probably
just keep it as 2 loops and be done with it, or if you have more than one
place you do this, a small function might be in order. Then it would be:

nullarr(arr);

or some such. You could even templatize it ot make it generic for all 2D
array uses.

In practice, you would prefer *anything*, UB included, to a simple

char * arr[X][Y] = {};

Why?
 
J

Joe Greer

Where? I know that when the original C standard was being
drafted, great care was taken to allow "fat" bounds checking
pointers, and that every time there was a doubt, the C committee
has clarified that they meant what they said. Your suggestion
is undefined behavior. (In practice, of course, I can't imagine
an effective implementation where it didn't work.)

Well, all the arithmetic mumbo jumbo in dcl.Array/6,7,8 implies it to me.
Note, I didn't say it says that, just implies it. Having read it again
with my lawyer hat on and turning off any assumptions, it does allow for
padding between arrays. So, my ill thought out example of how to use
std::fill() causes undefined behavior, much like the memset() example else
thread. I suspect it would actually work with most implementations though.

joe
 
J

Joe Greer

Gennaro Prota said:
Joe said:
Hello, is there something neat in the c++ standard library that can
help me set all elements of a two-dimensional array of pointers to
NULL? Like fill_n(), maybe? Right now, I'm using two for loops (one
nested) and wanted to know what alternatives there are. My compiler
ships with a preliminary TR1-implementation.
Another thing I need to do is to call delete on the pointers in the
array at some other point in the program, am I stuck with the two
for loops there?

- Eric

The standard certainly implies that you can treat:

char * arr[X][Y]

as

char * arr[X*Y]

so...

something like:

std::fill(reinterpret_cast<char **>(arr),
reinterpret_cast<char **>(arr) + X*Y, 0);

Should work. It seems awfully obfuscated to me though. I would
probably just keep it as 2 loops and be done with it, or if you have
more than one place you do this, a small function might be in order.
Then it would be:

nullarr(arr);

or some such. You could even templatize it ot make it generic for
all 2D array uses.

In practice, you would prefer *anything*, UB included, to a simple

char * arr[X][Y] = {};

Why?

Well, I was assuming he wanted to reuse the array. If we are only talking
about the initial declaration, your version wins hands down.

joe
 
J

James Kanze

James said:
The standard actually does guarantee "something" in argv[0],
just not what you might want.
No. The standard actually allows argc to be 0, in which case argv[0]
will be a null pointer (as per the standard).

Which is something: you can test for it.
Even if argc > 0, the standard still allows argv[0] to be an empty string.
But how many CLI programs have you seen that actually check that
argc>0 and that argv[0] actually contains something else than an empty
string before referring to argv[0] (eg. to print the command-line
syntax)? :p

Good question. (The first question, obviously, is how many
access argv[0] at all? The Unix tradition says that error
messages should start with the name of the program, but I find a
lot of programs don't do this, or simply hardware the name in.)
Posix allows the invoking process to specify the arg list, and
specifies "The argument arg0 should point to a filename that is
associated with the process being started by one of the exec
functions." It doesn't, however, say what happens if this isn't
the case (the call to exec fails?), and of course, "associated
with the process being started" is even vaguer than the wording
in the C++ standard (``argv[0] shall be the pointer to the
initial character of a NTMBS that represents the name used to
invoke the program or ""'').

(A quick check shows that both Solaris and Linux pass a null
pointer for argv[0], and the invoked process has argc == 0 and
argv[0] == NULL. Arguably, they should return with an EINVAL
error, given the text I just quoted.)

FWIW: the function I usually use for parsing the argument list
does an `` assert( argc > 0 ) ''. So I do test it. (And you
can argue that under Unix, at least, a program with argc == 0
has not been correctly started, and should just abort.)
 

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,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top