How to Properly use Array of Structures of C - arrays

I'm recently started learning about structures in C Language. I tried out a sample program to extend my learning curve. But, here in this subject, I'm facing few errors. Shall anyone please figure out the errors in the following program.
#include<stdio.h>
main() {
int i;
struct elements {
int z; /* Atomic Number */
float m; /* Mass Number */
char *name;
char *symbol;
};
struct elements e[5];
e[0] = (struct elements){1,1.008,"Hydrogen","H"};
e[1] = (struct elements){2,4.0026,"Helium","He"};
e[2] = (struct elements){3,6.94,"Lithium","Li"};
clrscr();
for(i=0;i<3;i++) {
printf("Element Name: %s\n",e[i].name);
printf("Symbol: %s\n",e[i].symbol);
printf("Atomic Number: %d\n",e[i].z);
printf("Atomic Mass: %0.2f\n",e[i].m);
}
getch();
return 0;
}
This shows the following Error messages:

Despite the other comments, if this is what you have to work with, then you'll still be wanting a solution.
Try:
struct elements e[5] = {
{1,1.008,"Hydrogen","H"},
{2,4.0026,"Helium","He"},
{3,6.94,"Lithium","Li"}
};
What you had would work on later compilers (although some will want char const * in the struct for name and symbol to accept string literals), but its actually not very pretty to read, nor is it necessary when you are defining the entire array.
If you do it this way, you can omit the array size (change [5] to []) and it will size according to the number of elements provided.

You aren't using a standard C compiler so you can't write the code in the standard C language.
You'll have to resort to the 1989 version of the C language known as "C89"/"C90". It doesn't support the compound literal feature (struct elements){1,1.008,"Hydrogen","H"};, because that one was added to the C language 23 years ago.

Related

std::array equivalent in C

I'm new to C and C++, and I've read that at least in C++ it's preferable to use std::array or std::vector when using vectors and arrays, specially when passing these into a function.
In my research I found the following, which makes sense. I suppose using std::vector would fix the problem of indexing outside of the variable's scope.
void foo(int arr[10]) { arr[9] = 0; }
void bar() {
int data[] = {1, 2};
foo(data);
}
The above code is wrong but the compiler thinks everything is fine and
issues no warning about the buffer overrun.
Instead use std::array or std::vector, which have consistent value
semantics and lack any 'special' behavior that produces errors like
the above.
(answer from bames53, thanks btw!)
What I want to code is
float foo(int X, int Y, int l){
// X and Y are arrays of length l
float z[l];
for (int i = 0; i < l; i ++){
z[i] = X[i]+Y[i];
}
return z;
}
int bar(){
int l = 100;
int X[l];
int Y[l];
float z[l];
z = foo(X,Y,l);
return 0;
}
I want this to be coded in C, so my question is is there a std::vector construct for C? I couldn't find anything on that.
Thanks in advance, also please excuse my coding (I'm green as grass in C and C++)
Standard C has nothing like std::vector or other container structures. All you get is built-in arrays and malloc.
I suppose using std::vector would fix the problem of indexing outside of the variable's scope.
You might think so, but you'd be wrong: Indexing outside of the bounds of a std::vector is just as bad as with a built-in array. The operator[] of std::vector doesn't do any bounds checking either (or at least it is not guaranteed to). If you want your index operations checked, you need to use arr.at(i) instead of arr[i].
Also note that code like
float z[l];
...
return z;
is wrong because there are no array values in C (or C++, for that matter). When you try to get the value of an array, you actually get a pointer to its first element. But that first element (and all other elements, and the whole array) is destroyed when the function returns, so this is a classic use-after-free bug: The caller gets a dangling pointer to an object that doesn't exist anymore.
The customary C solution is to have the caller deal with memory allocation and pass an output parameter that the function just writes to:
void foo(float *z, const int *X, const int *Y, int l){
// X and Y are arrays of length l
for (int i = 0; i < l; i ++){
z[i] = X[i]+Y[i];
}
}
That said, there are some libraries that provide dynamic data structures for C, but they necessarily look and feel very different from C++ and std::vector (e.g. I know about GLib).
Your question might be sensitive for some programmers of the language.
Using constructs of one language into another can be considered cursing as different languages have different design decisions.
C++ and C share a huge part, in a way that C code can (without a lot of modifications) be compiled as C++. However, if you learn to master C++, you will realize that a lot of strange things happen because how C works.
Back to the point: C++ contains a standard library with containers as std::vector. These containers make use of several C++ constructions that ain't available in C:
RAII (the fact that a Destructor gets executed when the instance goes out-of-scope) will prevent a memory leak of the allocated memory
Templates will allow type safety to not mix doubles, floats, classes ...
Operator overloading will allow different signatures for the same function (like erase)
Member functions
None of these exist in C, so in order to have a similar structure, several adaptions are required for getting a data structure that behaves almost the same.
In my experience, most C projects have their own generic version of data structures, often based on void*. Often this will look similar like:
struct Vector
{
void *data;
long size;
long capacity;
};
Vector *CreateVector()
{
Vector *v = (Vector *)(malloc(sizeof(Vector)));
memset(v, 0, sizeof(Vector));
return v;
}
void DestroyVector(Vector *v)
{
if (v->data)
{
for (long i = 0; i < v->size; ++i)
free(data[i]);
free(v->data);
}
free(v);
}
// ...
Alternatively, you could mix C and C++.
struct Vector
{
void *cppVector;
};
#ifdef __cplusplus
extern "C" {
#endif
Vector CreateVector()
void DestroyVector(Vector v)
#ifdef __cplusplus
}
#endif
vectorimplementation.cpp
#include "vector.h"
struct CDataFree
{
void operator(void *ptr) { if (ptr) free(ptr); }
};
using CData = std::unique_ptr<void*, CDataFree>;
Vector CreateVector()
{
Vector v;
v.cppVector = static_cast<void*>(std::make_unique<std::vector<CData>>().release());
return v;
}
void DestroyVector(Vector v)
{
auto cppV = static_cast<std::vector<CData>>(v.cppVector);
auto freeAsUniquePtr = std::unique_ptr<std::vector<CData>>(cppV);
}
// ...
The closest equivalent of std::array in c is probably a preprocessor macro defintion like
#define ARRAY(type,name,length) \
type name[(length)]

My C programming is rusty and i'm having some issues

I am trying to declare a data structure in c and set some variables but I'm having a bit of trouble.
struct point {
float *x;
float *y;
float *z;
};
this struct is 24 bytes long so that's fine by me.
const unsigned int sz = 1<<24;
struct point _points[sz];
for(int i = 0; i < sz; ++i)
{
_points[i].x = get_rand_float();
_points[i].y = get_rand_float();
_points[i].z = get_rand_float();
}
// get_rand_float() returns a pointer to float;
The problem that I am having is that the application will crash.
I playing with the code a bit it seems that maybe 1<<24 is too large? Bringing it down to 1<<14 the program runs just fine.
That brings me to another question, why would 1<<24 or about 16 million ints cause my program to crash? It's a fairly trivial program just int main boilerplate and this struct?
You don't want a structure of pointers to floats:
struct point {
float *x;
float *y;
float *z;
};
You want a structure of floats:
struct point {
float x;
float y;
float z;
};
In your code, sz is int variable, not an array. So, techinicaly you cannot use the array subscript operator on sz. That code should not compile.
Maybe, you wanted to write something like
_points[i].x = get_rand_float();
But then again, it depends on get_rand_float() return type. It has to return a float * (which is not very likely seeing the function name).
In case, if get_rand_float() returns afloat value, and you want to store the returned value, then you don't need to use pointers as your structure member variable. You can simply use float x; and so on.
One possible problem is that your array of points is too large for the stack. See here. You could fix that by a dynamic memory allocation, something like:
struct point *_points = malloc(sz*sizeof(struct point));
And of course, don't forget to free the memory when finished.
EDIT: Based on your edit, your crash occurs when you use a massive struct size (1<<24), or 16,777,216 items in the struct. Borrowing an answer from here:
Size limitation of C structure
It would appear that you may be violating C standard by having over 65535 bytes in an object. Since 1<<14 works, which is only 16384, that might be why. To verify, try using anything above 1<<16 - those should all crash because it would be over 65535.
On a side note, it would be helpful if you post the actual error message you get so we have a better idea of what is going on. :)
---Pre-Author Edit Answer---
Assuming get_rand_float() returns what it's supposed to, the problem is that sz is an int, not a struct. It should look like:
int sz = 24;
struct point _points[sz];
for(int i = 0; i < sz; ++i)
{
_points[i].x = get_rand_float();
_points[i].y = get_rand_float();
_points[i].z = get_rand_float();
}
Others have pointed out your two main problems (size too large, and you should be using float not float* in your struct). But there is another potential problem, too: you should not get into the habit of beginning an identifier name with an underscore, because, from Section 7.1.3 of the 1999 C standard:
All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
Each macro name in any of the following subclauses (including the future library directions) is reserved for use as specified if any of its associated headers is included; unless explicitly stated otherwise (see 7.1.4).
All identifiers with external linkage in any of the following subclauses (including the future library directions) are always reserved for use as identifiers with external linkage.154
Each identifier with file scope listed in any of the following subclauses (including the future library directions) is reserved for use as a macro name and as an identifier with file scope in the same name space if any of its associated headers is included.
Keeping apart the big size of the array,your program is mainly crashing because there no memory allocated to the pointer variables x,y and z.
You have to allocate memory to the variables before assigning any values.
for(int i = 0; i < sz; ++i)
{
sz[i].x = get_rand_float(); <--- getting crash here!
sz[i].y = get_rand_float();
sz[i].z = get_rand_float();
}
for(i=0;i<sz;i++)
{
_points[i].x =(float *) malloc(sizeof(float));
_points[i].y = (float *) malloc(sizeof(float));
_points[i].z = (float *) malloc(sizeof(float));
*( _points[i].x) = get_rand_float();
*( _points[i].y) = get_rand_float();
*( _points[i].z) = get_rand_float();
}
for(i=0;i<sz;i++)
{
printf("%f %f %f ",*( _points[i].x), *(_points[i].y), *(_points[i].z));
printf("\n");
}
You can make your program simple by taking float as members of the structure instead of float pointers.
struct point {
float x;
float y;
float z;
};
int main()
{
int i;
for(i=0;i<sz;i++)
{
_points[i].x = get_rand_float();
_points[i].y = get_rand_float();
_points[i].z = get_rand_float();
}
for(i=0;i<sz;i++)
{
printf("%f %f %f ", _points[i].x, _points[i].y, _points[i].z);
printf("\n");
}

how to display the name of a struct variable in c? [duplicate]

This question already has answers here:
Get list of C structure members
(6 answers)
Closed 7 years ago.
I have two variables called x and y in a structure called mystruct, when I have the program I want to be able to display the variable names with its value like this.
mystruct.x --> 3, mystruct.y --> 5
Is there a way to do this without just putting mystruct.x in the printf like a string in c?
you can't extract the name of the struct in a smart and clean way.
the possibility to call the type of a variable or a struct is called "Reflection" - the application ability to reflect upon itself (either in compile or runtime) and extract data like the type, typename, inner variables etc.
this is not supported at all in C. thinking about it , C doesn't care- a struct is basically a row in the memory (like any other variable in C, actually).
you can however , make a not-so-smart implementation that stores the typename equivilant to the memory address :
struct memory_address_to_type_name{
char type_name [20],
void* memory_address
} name_memory_address_map[50];
char* get_name (void* variable){
int i;
for (i=0;i<50;i++){
if (variable == name_memory_address_map[i].memory_address)){
return name_memory_address_map[i].type_name;
}
}
return "not found";
}
int push_name (void* variable , char* type_name){
int i;
for (i=0;i<50;i++){
if (strcmp(name_memory_address_map[i].type_name,"") == 0){
name_memory_address_map[i].memory_address = variable;
strcpy(name_memory_address_map[i].type_name,type_name);
}
return 1;
}
return 0;
}
}
int main (void){
myStruct x;
push_name (&x,"myStruct");
//other code
printf("%s --> %d",get_name(x),x.my_member);
}
of course , this is not a complete example. you do want to use a linked list instead of a ad-hoc bounded array , do much more protecting against overflows and out of arrays errors , etc. this is only the idea.
as a side note (and I might get downvoted for this), as a C++ developer, your problem could be much more easily solved in C++ by using a typeid(x).name() (if the implementation does return normal string , like VC++ implementation) , or reproduce the solution above with std::map and std::string . but this is a side note only.
do you mean something like this: http://ideone.com/3UeJHv:
#include <stdio.h>
#define PRINT_INT(X) printf(#X"-->%d\n",X)
#define PRINT_STUDENT(X) printf(#X".x-->%d " #X".y-->%d\n" ,X.x ,X.y)
struct student
{
int x;
int y;
};
int main()
{
int c = 10;
PRINT_INT(c);
struct student stud1 = {200 , 300};
struct student stud2 = {400 , 500};
PRINT_STUDENT(stud1);
PRINT_STUDENT(stud2);
return 0;
}
output:
c-->10 stud1.x-->200 stud1.y-->300 stud2.x-->400 stud2.y-->500

using #define for defining struct objects

I came across this simple program somewhere
#include<stdio.h>
#include<stdlib.h>
char buffer[2];
struct globals {
int value;
char type;
long tup;
};
#define G (*(struct globals*)&buffer)
int main ()
{
G.value = 233;
G.type = '*';
G.tup = 1234123;
printf("\nValue = %d\n",G.value);
printf("\ntype = %c\n",G.type);
printf("\ntup = %ld\n",G.tup);
return 0;
}
It's compiling (using gcc) and executing well and I get the following output:
Value = 233
type = *
tup = 1234123
I am not sure how the #define G statement is working.
How G is defined as an object of type struct globals ?
First, this code has undefined behavior, because it re-interprets a two-byte array as a much larger struct. Therefore, it is writing past the end of the allocated space. You could make your program valid by using the size of the struct to declare the buffer array, like this:
struct globals {
int value;
char type;
long tup;
};
char buffer[sizeof(struct globals)];
The #define is working in its usual way - by providing textual substitutions of the token G, as if you ran a search-and-replace in your favorite text editor. Preprocessor, the first stage of the C compiler, finds every entry G, and replaces it with (*(struct globals*)&buffer).
Once the preprocessor is done, the compiler sees this code:
int main ()
{
(*(struct globals*)&buffer).value = 233;
(*(struct globals*)&buffer).type = '*';
(*(struct globals*)&buffer).tup = 1234123;
printf("\nValue = %d\n",(*(struct globals*)&buffer).value);
printf("\ntype = %c\n",(*(struct globals*)&buffer).type);
printf("\ntup = %ld\n",(*(struct globals*)&buffer).tup);
return 0;
}
The macro simply casts the address of the 2-character buffer buf into a pointer to the appropriate structure type, then de-references that to produce a struct-typed lvalue. That's why the dot (.) struct-access operator works on G.
No idea why anyone would do this. I would think it much cleaner to convert to/from the character array when that is needed (which is "never" in the example code, but presumably it's used somewhere in the larger original code base), or use a union to get rid of the macro.
union {
struct {
int value;
/* ... */
} s;
char c[2];
} G;
G.s.value = 233; /* and so on */
is both cleaner and clearer. Note that the char array is too small.

What does it mean that automatic structures and arrays may now also be initialized?

In the beginning of chapter 6: Structures of the book by Brian W. Kernighan and Dennis M. Ritchie, there is a paragraph that I can't understand.
The main change made by the ANSI standard is to define structure assignment - structures may be copied and assigned to, passed to functions, and returned by functions. This has been supported by most compilers for many years, but the properties are now precisely defined. Automatic structures and arrays may now also be initialized.
What does it mean that automatic structures and arrays may now also be initialized? I'm pretty sure that automatic, namely local variables should be initialized manually. Would you please help me understand what it means?
In pre-standard C (meaning 'before the C89 standard', or a long time ago), you could not write:
int function(int i)
{
int array[4] = { 1, 2, 3, 4 };
struct { int x; int y; } x = { 1, 2 };
struct { int x; int y; } a[] = { { 2, 3 }, { 3, 4 } };
...code using array, x, a...
return x.y + a[!!i].x + array[3];
}
Now you are allowed to do all these.
Also, in K&R 1st Edition C (circa 1978), you were not allowed to write:
int another()
{
struct { int x; int y; } a, b;
a.x = 1;
a.y = 0;
b = a; /* Not allowed in K&R 1 */
some_other_func(a, b); /* Not allowed in K&R 1 */
some_other_func(&a, &b); /* Necessary in K&R 1 */
...
}
You could also only return pointers to structures (as well as pass pointers to structures). IIRC, some C compilers actually allowed the non-pointer notation, but converted the code behind the scenes to use pointers. However, the structure assignment and structure passing and structure returning limitations were removed from C well before the standard (shortly after K&R 1 was published). But not all compilers supported these features because there wasn't a standard for them to conform to.
It means you can do stuff like this:
typedef struct { int a; float b; } foo;
int main(void) {
foo f = { 42, 3.14 }; // Initialization
...
}

Resources