By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,370 Members | 1,590 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,370 IT Pros & Developers. It's quick & easy.

Initialization of a const matrix implemented as pointer-to-pointer

P: n/a
Subject: Initialization of a const matrix implemented as pointer-to-pointer

Hello everyone.

I've got the following matrix definition in a source file

static const char **a;

I need it to be initialized as an array of strings, something like

static const char **a = {"Alpha", "Beta", Charlie"};

I know the number of strings and their maximum length, but I can't use a
stack-allocated matrix for compatibility reasons with another piece of
code, which simply defines a

char** strings

to which the matrix has to be assigned to.

I thought I could write a static const declaration for each string

static const str1[MAX_LENGTH] ="Alpha"

and then declare the matrix as

static const char* a[NUM_OF_STRINGS] = {str1,str2,...}

would it be correct?

thanks for your attention

AT

Sep 10 '08 #1
Share this Question
Share on Google+
17 Replies


P: n/a
Andrea Taverna (Tavs) wrote:
Subject: Initialization of a const matrix implemented as pointer-to-pointer

Hello everyone.

I've got the following matrix definition in a source file

static const char **a;

I need it to be initialized as an array of strings, something like

static const char **a = {"Alpha", "Beta", Charlie"};

I know the number of strings and their maximum length, but I can't use a
stack-allocated matrix for compatibility reasons with another piece of
code, which simply defines a

char** strings

to which the matrix has to be assigned to.

I thought I could write a static const declaration for each string

static const str1[MAX_LENGTH] ="Alpha"

and then declare the matrix as

static const char* a[NUM_OF_STRINGS] = {str1,str2,...}

would it be correct?

thanks for your attention
Looks OK to me.
You don't need NUM_OF_STRINGS.
And if you have the strings available to write
static const str1[MAX_LENGTH] ="Alpha";
then you don't need str1 either.

How about
static const char *a[] = {"Alpha", "Beta", Charlie"};
?

/* BEGIN new.c output */

Alpha
Beta
Charlie

/* END new.c output */

/* BEGIN new.c */

#include <stdio.h>

int main(void)
{
static const char *a[] = {"Alpha", "Beta", "Charlie"};
size_t index;

puts("/* BEGIN new.c output */\n");
for (index = 0; index != sizeof a / sizeof *a; ++index) {
puts(a[index]);
}
puts("\n/* END new.c output */");
return 0;
}

/* END new.c */

--
pete
Sep 10 '08 #2

P: n/a
On Wed, 10 Sep 2008 13:57:47 +0200, "Andrea Taverna (Tavs)"
<a.****@libero.itwrote:
>Subject: Initialization of a const matrix implemented as pointer-to-pointer

Hello everyone.

I've got the following matrix definition in a source file

static const char **a;
In this case, sizeof a will probably be 4 or 8.
>
I need it to be initialized as an array of strings, something like

static const char **a = {"Alpha", "Beta", Charlie"};

I know the number of strings and their maximum length, but I can't use a
stack-allocated matrix for compatibility reasons with another piece of
code, which simply defines a

char** strings
>
to which the matrix has to be assigned to.
There should be no problem "assigning the array" to this pointer.
>
I thought I could write a static const declaration for each string

static const str1[MAX_LENGTH] ="Alpha"

and then declare the matrix as

static const char* a[NUM_OF_STRINGS] = {str1,str2,...}
If NUM_OF_STRINGS is 3 (to be consistent with your example), sizeof a
will probably be 12 or 24.
>
would it be correct?
It depends on how you plan to use a.

In the first example, is a true pointer. It can appear on the left
side of the assignment operator. In the second, a is an array which
cannot appear there. However, in both cases, a can appear on the
right of the assignment operator.

If all you want is a variable name that can be subscripted to evaluate
to different strings, then the second will work. If you delete the
"static", it will become a "stack allocated matrix" (technically an
automatic array of char*). When the array name "a" appears in an
expression context other than as the operand of sizeof and &, it will
be converted to the address of a[0] with type "pointer to type of
a[0]". Since a is an array of char*, a[0] is the first char* in the
array. The type "pointer to type of a[0]" is simply "pointer to
char*" also known as char**. Therefore you can assign the array name
"a" to the variable "strings" in the other code.

On the other hand, if you need a true pointer that can be reassigned
to point to different sets of strings, then something of the form:

const astr1[] = "Alpha";
...
const astrx[] = "Omega";
const bstr1[] = "Alef";
...
const bstrx[] = "Tav";
const char* A[] = {astr1,...,astrx};
const char* B[] = {bstr1,...,bstrx};
const char **a = A;
...
a = B;
and anywhere in your code you can say
strings = a;

--
Remove del for email
Sep 10 '08 #3

P: n/a
Barry Schwarz ha scritto:
In this case, sizeof a will probably be 4 or 8.
>I need it to be initialized as an array of strings, something like

static const char **a = {"Alpha", "Beta", Charlie"};

I know the number of strings and their maximum length, but I can't use a
stack-allocated matrix for compatibility reasons with another piece of
code, which simply defines a

char** strings
> to which the matrix has to be assigned to.

There should be no problem "assigning the array" to this pointer.
Actually there is. GCC warns that they're not compatible
On the other hand, if you need a true pointer that can be reassigned
to point to different sets of strings, then something of the form:

const astr1[] = "Alpha";
...
const astrx[] = "Omega";
const bstr1[] = "Alef";
...
const bstrx[] = "Tav";
const char* A[] = {astr1,...,astrx};
const char* B[] = {bstr1,...,bstrx};
const char **a = A;
...
a = B;
and anywhere in your code you can say
strings = a;
that's precisely what I'm going to do.

Thanks

AT
Sep 10 '08 #4

P: n/a
Ok, I've tried both ways, Barry's and Pete's. GCC still wars about
compatibility, but it behaves correctly at run time, so the problem is set.

Thank you :D

AT
Sep 10 '08 #5

P: n/a
Andrea Taverna (Tavs) wrote:
Barry Schwarz ha scritto:
In this case, sizeof a will probably be 4 or 8.
I need it to be initialized as an array of strings, something like

static const char **a = {"Alpha", "Beta", Charlie"};

I know the number of strings and their maximum length, but I can't use a
stack-allocated matrix for compatibility reasons with another piece of
code, which simply defines a

char** strings
to which the matrix has to be assigned to.
There should be no problem "assigning the array" to this pointer.

Actually there is. GCC warns that they're not compatible
That's because the second declaration should be

const char** strings;

If you don't have the power to change the declaration of 'strings',
check the documentation of the other piece of code very carefully. Is
that code going to attempt to write to those strings? If not, then it
was a mistake on the designer's part to declare "strings" without
using const. However, it's a mistake you can deal with by simply use a
cast:

strings = (char**)a;

However, it if will be writing to the strings, then this is not an
appropriate approach; the memory allocated for string literals is not
necessarily writable. In that case, follow the example given below,
but remove the word "const" wherever it appears:
On the other hand, if you need a true pointer that can be reassigned
to point to different sets of strings, then something of the form:

const astr1[] = "Alpha";
...
const astrx[] = "Omega";
const bstr1[] = "Alef";
...
const bstrx[] = "Tav";
const char* A[] = {astr1,...,astrx};
const char* B[] = {bstr1,...,bstrx};
const char **a = A;
...
a = B;
and anywhere in your code you can say
strings = a;
Sep 10 '08 #6

P: n/a
"Andrea Taverna (Tavs)" <a.****@libero.itwrites:
Ok, I've tried both ways, Barry's and Pete's. GCC still wars about
compatibility, but it behaves correctly at run time, so the problem is
set.
Don't be satisfied with code that produces warnings. Understand why
the warning is being produced. Most of the time, you should fix the
code so the warning goes away (note: adding a cast is rarely the right
fix). In some cases, it makes sense to leave the code as it is and
accept the warning, but most warnings indicate a real problem in the
code, one that's likely to bite you later on.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 10 '08 #7

P: n/a
On Wed, 10 Sep 2008 16:16:23 +0200, "Andrea Taverna (Tavs)"
<a.****@libero.itwrote:
>Barry Schwarz ha scritto:
>In this case, sizeof a will probably be 4 or 8.
>>I need it to be initialized as an array of strings, something like

static const char **a = {"Alpha", "Beta", Charlie"};

I know the number of strings and their maximum length, but I can't use a
stack-allocated matrix for compatibility reasons with another piece of
code, which simply defines a

char** strings
>> to which the matrix has to be assigned to.

There should be no problem "assigning the array" to this pointer.

Actually there is. GCC warns that they're not compatible
I would be nice if you told us what the warning said. It is probably
a complaint about loss of "const" so remove that qualifier from your
code.
>
>On the other hand, if you need a true pointer that can be reassigned
to point to different sets of strings, then something of the form:

const astr1[] = "Alpha";
...
const astrx[] = "Omega";
const bstr1[] = "Alef";
...
const bstrx[] = "Tav";
const char* A[] = {astr1,...,astrx};
const char* B[] = {bstr1,...,bstrx};
const char **a = A;
...
a = B;
and anywhere in your code you can say
strings = a;

that's precisely what I'm going to do.
You will still have the const problem.

--
Remove del for email
Sep 11 '08 #8

P: n/a
>I would be nice if you told us what the warning said. It is probably
>a complaint about loss of "const" so remove that qualifier from your
code.
Sure.
I don't have the code at hand. More or less it says:
"Warning: assignment between incompatible types"

We fixed it by adjusting the declaration of the 'strings' field.
Now they're both declared as const char**, and the problem would be solved.
However I had to change the C standard from gnu89 (gcc's default) to
c99, and with the following piece of code

const char * a [] =
{
"alpha", "beta","charlie"
};

const struct my_structure my_s = (const struct my_structure)
{
.x = 10;
.strings = a; // <- Error
};

and the latter standard it complains with the following message:
"Error: initializer element is not constant"
With gnu89 it compiles fine.
Sep 19 '08 #9

P: n/a
On Fri, 19 Sep 2008 19:43:53 +0200, "Andrea Taverna (Tavs)"
<a.****@libero.itwrote:
I would be nice if you told us what the warning said. It is probably
a complaint about loss of "const" so remove that qualifier from your
code.
Sure.
I don't have the code at hand. More or less it says:
"Warning: assignment between incompatible types"

We fixed it by adjusting the declaration of the 'strings' field.
Now they're both declared as const char**, and the problem would be solved.
However I had to change the C standard from gnu89 (gcc's default) to
c99, and with the following piece of code

const char * a [] =
{
"alpha", "beta","charlie"
};

const struct my_structure my_s = (const struct my_structure)
{
.x = 10;
.strings = a; // <- Error
};

and the latter standard it complains with the following message:
"Error: initializer element is not constant"
With gnu89 it compiles fine.
If this code is outside of a function then my_s has static duration.
Initialization of a static object must be a compile time constant
since it occurs before any code is executed. The same restriction
applies to compound literals outside of a function body (6.5.2.5-3).

I can't help with gnu89 except to suggest that you specify the
appropriate options to prohibit extensions.

--
Remove del for email
Sep 20 '08 #10

P: n/a
Barry Schwarz wrote:
If this code is outside of a function then my_s has static duration.
Initialization of a static object must be a compile time constant
since it occurs before any code is executed. The same restriction
applies to compound literals outside of a function body (6.5.2.5-3).
Uh, yes. I forgot to specify that the initialization takes place in the
global scope (in a source file).

Ehm, could I ask you how I should change the code to have the error
fixed? I couldn't figure it out.
thanks

Andrea
Sep 22 '08 #11

P: n/a
On Mon, 22 Sep 2008 13:59:22 +0200, "Andrea Taverna (Tavs)"
<a.****@libero.itwrote:
>Uh, yes. I forgot to specify that the initialization takes place in the
global scope (in a source file).

Ehm, could I ask you how I should change the code to have the error
fixed? I couldn't figure it out.
To answer your question:

If you can limit yourself to C99 systems, you might be able to
use a compound literal.

Otherwise, I think you need to cheat. Create an
initialization function which you will call early in main. In this
function, access the const structures using non-const pointers and
initialize everything. Mark the structures volatile so the compiler
doesn't optimize away any accesses thinking it knows what values are
in the structures.

The real question is why are the structures at file scope. If the
answer is that they are used so frequently that you cannot afford to
pass them (or their addresses) to all the different functions that
need them then rethink how you access them. If you define the
structures in main, you can create global pointers to const, assign
values to the pointers in main, and have all the other functions
access the structures through the pointers. Since the structures are
no longer static, you have more flexibility in how you initialize
them.

--
Remove del for email
Sep 23 '08 #12

P: n/a
"Andrea Taverna (Tavs)" <a.****@libero.itwrites:
Barry Schwarz ha scritto:
>To answer your question:

If you can limit yourself to C99 systems, you might be able to
use a compound literal.

If you mean this:
my_s {
Did you have "my_s = {"? What you have posted look like a syntax error.
.x = 10,
.strings = {"alpha","beta","gamma"}
}
No, a compound literal would look like this:

.strings = (const char *[]){"alpha","beta","gamma"}

(again, this is C99).

--
Ben.
Sep 23 '08 #13

P: n/a
Ben Bacarisse ha scritto:
>
Did you have "my_s = {"? What you have posted look like a syntax error.
Oh, yes, I meant

const struct my_structure my_s = (const struct my_structure)
{
.x = 10;
.strings = {"alpha","beta","gamma"}
};

No, a compound literal would look like this:

.strings = (const char *[]){"alpha","beta","gamma"}
Gotcha. now it accept the assignment, but there's still that error:
initializer element is not constant

Andrea
Sep 23 '08 #14

P: n/a
"Andrea Taverna (Tavs)" <a.****@libero.itwrites:
Ben Bacarisse ha scritto:
<snip>
>No, a compound literal would look like this:

.strings = (const char *[]){"alpha","beta","gamma"}

Gotcha. now it accept the assignment, but there's still that error:
initializer element is not constant
You'd better post a small example that shows the problem. On my
system the above compiles silently. (BTW, that line is not,
technically, an assignment -- it is part of an initialisation.)

--
Ben.
Sep 24 '08 #15

P: n/a
Ben Bacarisse ha scritto:
You'd better post a small example that shows the problem. On my
system the above compiles silently.
struct my_structure
{
int x;
const char ** strings;
};

const struct my_structure my_s = (const struct my_structure)
{
.x = 10,
.strings = (const char *[]){"alpha","beta","charlie"}
}; // <-error

The compiler (gcc4.3.0-8 for Red Hat) says the error is on the last line
(BTW, that line is not,
technically, an assignment -- it is part of an initialisation.)
Gotcha

thanks

Andrea
Sep 24 '08 #16

P: n/a
"Andrea Taverna (Tavs)" <a.****@libero.itwrites:
Ben Bacarisse ha scritto:
>You'd better post a small example that shows the problem. On my
system the above compiles silently.

struct my_structure
{
int x;
const char ** strings;
};

const struct my_structure my_s = (const struct my_structure)
Just leave out this "top-level" compound literal.
{
.x = 10,
.strings = (const char *[]){"alpha","beta","charlie"}
}; // <-error
I.e. write:

const struct my_structure my_s = {
.x = 10,
.strings = (const char *[]){"alpha","beta","charlie"}
};

--
Ben.
Sep 24 '08 #17

P: n/a
Now it WORKS! thank you!

Andrea
Sep 24 '08 #18

This discussion thread is closed

Replies have been disabled for this discussion.