Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > C/C++ question about dynamic "static struct"

Reply
Thread Tools

C/C++ question about dynamic "static struct"

 
 
gus gassmann
Guest
Posts: n/a
 
      10-17-2012
Hi,

I have a static struct, defined in a C header file as something like

typedef struct
SomeStruct {
char *name;
int kind;
int value;
}

and I need to supply (in C++) values to an array of this type. I
understand that I can set *static* values by

static SomeStruct
myStruct[] = {
{"name1", 1, 17},
{"name2", 7, 25},
{"name3", 3, 6},
{"name4", 0,117}
};

However, I need to set dynamic values along these lines (I know that the
code does not work):

static SomeStruct
myStruct[] = {
{name[0], kind[0], val[0]},
{name[1], kind[1], val[1]},
...
{name[n], kind[n], val[n]},
};

where both the values and the number of values are only known at
runtime. I cannot change the definition in the header file; I am not
even sure that what I want to do is possible. Any ideas?

Thanks

gus


 
Reply With Quote
 
 
 
 
Noob
Guest
Posts: n/a
 
      10-17-2012
gus gassmann wrote:

First of all, it is not clear what "C/C++" means.
There is C, and there is C++.

> I have a static struct, defined in a C header file as something like
>
> typedef struct
> SomeStruct {
> char *name;
> int kind;
> int value;
> }


Nit: you should copy/paste the EXACT code. The above does not make sense.
(warning: useless storage class specifier in empty declaration)

I think you meant:

typedef struct { char *name; int kind; int value; } SomeStruct;

which defines an anonymous struct, and defines "SomeStruct"
as a synonym. (AFAIU, this is done "automatically" in C++)

> and I need to supply (in C++) values to an array of this type. I
> understand that I can set *static* values by
>
> static SomeStruct
> myStruct[] = {
> {"name1", 1, 17},
> {"name2", 7, 25},
> {"name3", 3, 6},
> {"name4", 0,117}
> };
>
> However, I need to set dynamic values along these lines (I know that the
> code does not work):
>
> static SomeStruct
> myStruct[] = {
> {name[0], kind[0], val[0]},
> {name[1], kind[1], val[1]},
> ...
> {name[n], kind[n], val[n]},
> };
>
> where both the values and the number of values are only known at
> runtime. I cannot change the definition in the header file; I am not
> even sure that what I want to do is possible. Any ideas?


If the size of the array is not known at compile-time, then you
need dynamic memory allocation.

In C, you could write:

#include <stdlib.h>
typedef struct { char *name; int kind; int value; } SomeStruct;
static SomeStruct *array;
void array_init(int n, char **name, int *kind, int *value)
{
int i;
array = malloc(n * sizeof *array);
for (i = 0; i < n; ++i)
{
SomeStruct temp = { name[i], kind[i], value[i] };
array[i] = temp;
}
}

In C++, they use new and new[] instead of malloc.

 
Reply With Quote
 
 
 
 
James Kuyper
Guest
Posts: n/a
 
      10-17-2012
On 10/17/2012 07:08 AM, Noob wrote:
> gus gassmann wrote:
>
> First of all, it is not clear what "C/C++" means.
> There is C, and there is C++.


In context, it means mixed-language programming. He has a C header file
declaring a struct type, and an array of that type which will be filled
in by calling a C++ function. The C++ standard defines how mixing C and
C++ works; the C standard does not, so this is fundamentally a C++ question.
--
James Kuyper
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      10-17-2012
On 10/17/2012 05:49 AM, gus gassmann wrote:
> Hi,
>
> I have a static struct, defined in a C header file as something like
>
> typedef struct
> SomeStruct {
> char *name;
> int kind;
> int value;
> }


That's not a valid typedef; it's not clear what you intended, but given
the code below, you should probably have moved 'SomeStruct' after the
right curly bracket, and then appended a semicolon.

> and I need to supply (in C++) values to an array of this type. I
> understand that I can set *static* values by
>
> static SomeStruct
> myStruct[] = {
> {"name1", 1, 17},
> {"name2", 7, 25},
> {"name3", 3, 6},
> {"name4", 0,117}
> };
>
> However, I need to set dynamic values along these lines (I know that the
> code does not work):
>
> static SomeStruct
> myStruct[] = {
> {name[0], kind[0], val[0]},
> {name[1], kind[1], val[1]},
> ...
> {name[n], kind[n], val[n]},
> };
>
> where both the values and the number of values are only known at
> runtime. I cannot change the definition in the header file; I am not
> even sure that what I want to do is possible. Any ideas?


It isn't possible to do this in the initializer of a static object. That
initializer is evaluated at the time the object is created, which for
objects with static storage duration, occurs at the start of the
program. If you want the values to be set at run time, you'll have to
use assignment expressions to fill it in, not initialization.

If the array's length is not known until run time, you can't make it a
static array; the best you can do is a static pointer to a dynamically
allocated array, which should be initialized with a null pointer. Make
sure that your code is written in such a way as to guarantee that the
pointer is not dereferenced while null. You could use malloc() to
allocate the array, in either language. However, since the array will be
filled in by C++ code, you'd be better off using a 'new' expression,
which has better type safety.
--
James Kuyper
 
Reply With Quote
 
Richard Damon
Guest
Posts: n/a
 
      10-17-2012
On 10/17/12 5:49 AM, gus gassmann wrote:
>
> static SomeStruct
> myStruct[] = {
> {name[0], kind[0], val[0]},
> {name[1], kind[1], val[1]},
> ...
> {name[n], kind[n], val[n]},
> };
>
> where both the values and the number of values are only known at
> runtime. I cannot change the definition in the header file; I am not
> even sure that what I want to do is possible. Any ideas?
>
> Thanks
>
> gus
>
>


Fundamental problem! A static (or any global) object MUST have a
compiler known size, you can NOT have its size determined at run time.

If its size is not know at compile time, then its memory allocation must
be dynamic. (In C99, but not C++ except as an extension, it could also
be of storage type auto).

This is a fundamental issue, any static/global object has a fixed
address range, so a fixed size. you need something without a fixed
address to store something of variable size (unless you can cap the size
and just always allocate the most space it will ever need).

In C and C++, this is done with the heap.

You could possible change your definition of myStruct to

static SomeStruct *myStruct;

And then create the array of SomeStructs and assign its address to
myStruct.
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      10-17-2012
On 10/17/2012 08:35 AM, Richard Damon wrote:
> On 10/17/12 5:49 AM, gus gassmann wrote:

....
> If its size is not know at compile time, then its memory allocation must
> be dynamic. (In C99, but not C++ except as an extension, it could also
> be of storage type auto).


Use of the 'auto' keyword is completely unnecessary in C, because it can
only be used in contexts where the object would have automatic storage
duration whether or not you used that keyword. In C++ the 'auto' keyword
cannot be used for this purpose, because it has been given a different,
much more useful meaning. However, automatic storage duration is the
default for objects declared with block scope in both C and C++.
--
James Kuyper
 
Reply With Quote
 
Jorgen Grahn
Guest
Posts: n/a
 
      10-17-2012
On Wed, 2012-10-17, Noob wrote:
....
> In C++, they use new and new[] instead of malloc.


Actually, we usually use std::vector or other containers, so we don't
have to manage the memory manually. (It's unclear though if the OP is
allowed to to that or if he needs to keep a raw C array.)

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
 
Reply With Quote
 
gus gassmann
Guest
Posts: n/a
 
      10-17-2012
On 17/10/2012 8:08 AM, Noob wrote:
> gus gassmann wrote:
>
> First of all, it is not clear what "C/C++" means.
> There is C, and there is C++.
>
>> I have a static struct, defined in a C header file as something like
>>
>> typedef struct
>> SomeStruct {
>> char *name;
>> int kind;
>> int value;
>> }

>
> Nit: you should copy/paste the EXACT code. The above does not make sense.
> (warning: useless storage class specifier in empty declaration)
>
> I think you meant:
>
> typedef struct { char *name; int kind; int value; } SomeStruct;
>
> which defines an anonymous struct, and defines "SomeStruct"
> as a synonym. (AFAIU, this is done "automatically" in C++)
>
>> and I need to supply (in C++) values to an array of this type. I
>> understand that I can set *static* values by
>>
>> static SomeStruct
>> myStruct[] = {
>> {"name1", 1, 17},
>> {"name2", 7, 25},
>> {"name3", 3, 6},
>> {"name4", 0,117}
>> };
>>
>> However, I need to set dynamic values along these lines (I know that the
>> code does not work):
>>
>> static SomeStruct
>> myStruct[] = {
>> {name[0], kind[0], val[0]},
>> {name[1], kind[1], val[1]},
>> ...
>> {name[n], kind[n], val[n]},
>> };
>>
>> where both the values and the number of values are only known at
>> runtime. I cannot change the definition in the header file; I am not
>> even sure that what I want to do is possible. Any ideas?

>
> If the size of the array is not known at compile-time, then you
> need dynamic memory allocation.
>
> In C, you could write:
>
> #include <stdlib.h>
> typedef struct { char *name; int kind; int value; } SomeStruct;
> static SomeStruct *array;
> void array_init(int n, char **name, int *kind, int *value)
> {
> int i;
> array = malloc(n * sizeof *array);
> for (i = 0; i < n; ++i)
> {
> SomeStruct temp = { name[i], kind[i], value[i] };
> array[i] = temp;
> }
> }
>
> In C++, they use new and new[] instead of malloc.


Thanks to all who responded. As Jorgen Grahn surmised, I am not allowed
to change the C header file. I like Noob's solution, because it seems
simple and uses an idiom that I am familiar with. I therefore tried to
incorporate it into my file, making some adjustments I thought
necessary, and ran into trouble I cannot fathom. I would be grateful for
further assistance.

First, the C header file test.h. (I tried to simplify as much as
possible, while being faithful to the functionality I will need.)

#ifndef test_processed
#define test_processed

typedef struct
MyStruct {
char *name;
int kind;
int nextra;
} MyStruct;

#endif

Then the C++ code.

#include "test.h"
#include <sstream>

std::string get_str();
int get_dim();
int get_int();


int main(){
int ndim;
MyStruct *myStruct = 0;

ndim = get_dim();

myStruct = new MyStruct[ndim];
for (int i=0; i < ndim; i++)
{
myStruct[i] = {{(const)(get_str().c_str()), 0,
get_int()}};
}
return 0;
}

std::string get_str()
{
return "test";
}

int get_dim()
{
return 7;
}

int get_int()
{
return 2;
}

This gives the following error messages:

test.cpp: In function ‘int main()’:
test.cpp:18:34: error: ISO C++ forbids declaration of ‘type name’ with
no type
test.cpp:18:58: error: cast from ‘const char*’ to ‘const int’ loses
precision
test.cpp:18:74: warning: extended initializer lists only available with
-std=c++0x or -std=gnu++0x
test.cpp:18:74: warning: extended initializer lists only available with
-std=c++0x or -std=gnu++0x
test.cpp:18:74: error: no match for ‘operator=’ in ‘*(myStruct + ((long
unsigned int)(((long unsigned int)i) * 16ul))) = {{((const int)((long
int)get_str()().std::basic_string<_CharT, _Traits, _Alloc>::c_str [with
_CharT = char, _Traits = std::char_traits<char>, _Alloc =
std::allocator<char>]())), 0, get_int()}}’
test.h:2:10: note: candidate is: MyStruct& MyStruct:perator=(const
MyStruct&)

The first two have me confused. (Not that the others are any clearer,
but there I do not even understand what the error message means.) Isn't
'name' defined in the header file? And why does the compiler think I am
trying to cast to 'const int'?
BTW, I first tried

void main()

but the compiler complained that main() must return an integer, so I
changed it. I thought a void main was the proper thing.

Can anyone help me? (As you see, I no speaka da C++ so good, so please
be gentle.)

gus


 
Reply With Quote
 
Ike Naar
Guest
Posts: n/a
 
      10-17-2012
On 2012-10-17, gus gassmann <(E-Mail Removed)> wrote:
> Thanks to all who responded. As Jorgen Grahn surmised, I am not allowed
> to change the C header file. I like Noob's solution, because it seems
> simple and uses an idiom that I am familiar with. I therefore tried to
> incorporate it into my file, making some adjustments I thought
> necessary, and ran into trouble I cannot fathom. I would be grateful for
> further assistance.
>
> First, the C header file test.h. (I tried to simplify as much as
> possible, while being faithful to the functionality I will need.)
>
> #ifndef test_processed
> #define test_processed
>
> typedef struct
> MyStruct {
> char *name;
> int kind;
> int nextra;
> } MyStruct;
>
> #endif
>
> Then the C++ code.
>
> #include "test.h"
> #include <sstream>


Nothing from <sstream> is used, so why include it?
Something from <string> is used, so why not include it?

> std::string get_str();
> int get_dim();
> int get_int();
>
> int main(){
> int ndim;
> MyStruct *myStruct = 0;
> ndim = get_dim();
> myStruct = new MyStruct[ndim];


Get rid of the bogus initializations, and simply write:

int ndim = get_dim();
MyStruct *myStruct = new MyStruct[ndim];

> for (int i=0; i < ndim; i++)
> {
> myStruct[i] = {{(const)(get_str().c_str()), 0, get_int()}};


Here you're casting away const, and that is often a danger sign.
In this case, myStruct[i].name is set to point to a temporary value that
no longer exists after this statement.

> }
> return 0;
> }
>
> std::string get_str()
> {
> return "test";
> }
>
> int get_dim()
> {
> return 7;
> }
>
> int get_int()
> {
> return 2;
> }
>
> This gives the following error messages:
>
> test.cpp: In function ?int main()?:
> test.cpp:18:34: error: ISO C++ forbids declaration of ?type name? with
> no type
> test.cpp:18:58: error: cast from ?const char*? to ?const int? loses
> precision
> test.cpp:18:74: warning: extended initializer lists only available with
> -std=c++0x or -std=gnu++0x
> test.cpp:18:74: warning: extended initializer lists only available with
> -std=c++0x or -std=gnu++0x
> test.cpp:18:74: error: no match for ?operator=? in ?*(myStruct + ((long
> unsigned int)(((long unsigned int)i) * 16ul))) = {{((const int)((long
> int)get_str()().std::basic_string<_CharT, _Traits, _Alloc>::c_str [with
> _CharT = char, _Traits = std::char_traits<char>, _Alloc =
> std::allocator<char>]())), 0, get_int()}}?
> test.h:2:10: note: candidate is: MyStruct& MyStruct:perator=(const
> MyStruct&)
>
> The first two have me confused. (Not that the others are any clearer,
> but there I do not even understand what the error message means.) Isn't
> 'name' defined in the header file? And why does the compiler think I am
> trying to cast to 'const int'?


It's not clear which line is line 34, but the first error may have to
do with std::string being undeclared because <string> was not included.

> BTW, I first tried
> void main()
>
> but the compiler complained that main() must return an integer, so I
> changed it. I thought a void main was the proper thing.


It's not. What made you think so?
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      10-17-2012
On 10/17/2012 05:47 PM, gus gassmann wrote:
....
> First, the C header file test.h. (I tried to simplify as much as
> possible, while being faithful to the functionality I will need.)
>
> #ifndef test_processed
> #define test_processed
>
> typedef struct
> MyStruct {
> char *name;
> int kind;
> int nextra;
> } MyStruct;
>
> #endif
>
> Then the C++ code.
>
> #include "test.h"
> #include <sstream>
>
> std::string get_str();
> int get_dim();
> int get_int();
>
>
> int main(){
> int ndim;
> MyStruct *myStruct = 0;
>
> ndim = get_dim();
>
> myStruct = new MyStruct[ndim];
> for (int i=0; i < ndim; i++)
> {
> myStruct[i] = {{(const)(get_str().c_str()), 0,
> get_int()}};


That (const) is a syntax error. Perhaps you intended
const_cast<char*>(get_str().c_str())? That would, at least, be correct
syntax, and it would disable the warning message you would otherwise get
from assigning a const char* value in a char* object. However, it's not
a good idea to disable that warning message. Your "program shall not
alter any of the values stored in the character array" pointed at by the
pointer returned by c_str() (C++ 21.4.7.1p3), so I would not recommend
storing it in a char* variable. If your code (or any other code you pass
this struct to) makes the mistake of trying to write through
myStruct[i].name, your compiler won't warn you that you're making a
mistake.

That pointer may become invalid if at any time the std::string object
from which it cames gets modified (C++ 21.4.1p6). That's a general
warning that applies to any situation in which you call c_str(), though
it hardly matters in this case. This situation is much worse than that.
That's because the relevant string is the one returned by the call to
get_str(). Since that function returns the string by value, it is a
temporary object, whose lifetime will end as soon as the full-expression
containing that function call is finished being evaluated. In other
words, the pointer myStruct[i].name becomes invalid immediately after
being initialized.

You need to store the string returned by get_str(), allocate sufficient
memory for a copy of the contents of that string, and then copy the
string into that memory. I'm primarily a C programmer, so I may be
missing out some elegant C++ way of doing that, but the following
inelegant (and untested) code should do the job:

std::string s = get_str();
char *p = new char[s.size()];
s.copy(p, s.begin(), s.size());

Since you had to allocate this memory, you should make sure that it gets
deallocated by using the delete operator when you're done with it;
otherwise, you'll have a memory leak.

What Noob suggested corresponds to following this up with the following
code:

MyStruct temp = {s, 0, get_int()};
myStruct[i] = temp;

You tried to simplify by eliminating temp, but that's going too far with
simplification. The whole point of the temporary variable is that
initialization syntax can only be used when defining an object. It can't
be used as the right-hand-side (RHS) of an an assignment expression.

....
> This gives the following error messages:

....
> The first two have me confused. (Not that the others are any clearer,
> but there I do not even understand what the error message means.) Isn't
> 'name' defined in the header file? And why does the compiler think I am
> trying to cast to 'const int'?


It's probably trying to interpret your use of "(const)". I'm not sure
what it made of that syntax error, but there's no point in wondering
about it. Not only is the syntax wrong, but what you were attempting to
do using that syntax was also wrong. Just fix along the lines indicated
above.

> BTW, I first tried
>
> void main()
>
> but the compiler complained that main() must return an integer, so I
> changed it. I thought a void main was the proper thing.


No, int main() is the proper thing; void main() is a popular extension
to both C and C++, but neither language guarantees that it is supported.
On an implementation where that extension is not supported, you'll
probably get a warning message, but in principle your entire program
could malfunction if main() is declared that way.

> Can anyone help me? (As you see, I no speaka da C++ so good, so please
> be gentle.)


Your code involved several nasty misconceptions. I tried to explain the
problems as precisely as possible; I hope that didn't seem excessively
rough.


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Array question - How dynamic is dynamic? Ruby Student Ruby 4 04-09-2009 12:59 PM
Dynamic control on aspx page, dynamic location Chris Thunell ASP .Net 3 07-21-2004 04:52 PM
VPN between 2 Cisco routers (1 static, 1 dynamic) with access from stat --> dynamic over ISDN Hans-Peter Walter Cisco 3 01-21-2004 02:12 PM
Does Pix or cisco router support dynamic-to-dynamic IPSec VPN? c Cisco 2 01-13-2004 01:53 AM
Re: Dynamic Table with Dynamic LinkButtons Rick Glos ASP .Net 0 07-08-2003 01:09 PM



Advertisments