mallocing array of structs creates too small of an array - c

I'm a little new to structs in C and I'm having a problem with creating an array to store them. As the title says when I try to malloc out an array of structs my array ends up being too small by quite a large margin.
Here is my struct:
struct Points
{
char file_letter;
char *operation;
int cycle_time;
};
And here is how I'm trying to create the array:
struct Points *meta_data;
meta_data = malloc(number_of_delims * sizeof(struct Points));
number_of_delims is an int representing the number of Points I'm trying to create and therefore the number of elements in my array.
With number_of_delims being 64 I get an array size of about 8.
Note: this is more or less a project for school and I can't use typedef when declaring my struct as the prof. wants each struct explicitly declared as one each time it is used. This may actually be the source of my problem but we'll see!

struct Points *meta_data;
At this point we have a declaration of an object, meta_data that has type struct Points *... and struct Points *, being a pointer type, typically requires 8 bytes on common implementations. This is observable through the following program:
#include <stdio.h>
struct Points;
int main(void) {
struct Points *meta_data;
printf("sizeof meta_data: %zu\n", sizeof meta_data);
}
Remember, the sizeof operator evaluates the size of the type of the expression, which in this case is a pointer. Pointers don't carry size information about the arrays they point into. You need to keep that (i.e. preferably by pairing number_of_delims with meta_data, if you require both values later on).
With number_of_delims being 64 I get an array size of about 8.
No. You get an array size of exactly 64, as you've expected. Your pointer doesn't automatically carry that size information around with it (because you're expected to), so there is no portable way to come to the conclusion that your allocation can store 64 elements. The only way you could come to this conclusion is erroneously (i.e. by attempting to use sizeof, which as I've explained doesn't work as you expect).
As an exercise, what happens if you declare a pointer to an array of 64 struct Points, like so?
struct Points (*foo)[64] = NULL;
For a start, how many elements can NULL contain? What is sizeof foo and sizeof *foo? Do you see what I mean when I say sizeof evaluates the size of the type of an expression?

Related

Is it a valid operation to cast a void* pointer to char* pointer and doing pointer arithmetics on it?

I have a Pointer(void*) to a malloc'ed block/array in memory, and I know the Size of the data structure that is stored in that block. I want to be able to iterate over the block to get access to any single value.
Program knows:
that void* Pointer will point to the start of this malloc'ed block of memory.
the Size[in bytes] of each value, but not the data structure that is actually stored.
the Capacity[in bytes]: potential amount of those values(how much memory is allocated)
This means that I have malloc'ed: Capacity*Size_of_value bytes, and I want to get a pointer to any value that is inside that block, by:
Casting the void* Pointer into char* Pointer.
Adding a required multiple of Size_of_value to the char*Pointer: thus getting a pointer to any required value.
What I learned, is that adding N to a char* pointer, causes it to move forward by N bytes. And as I know that the pointer has to be moved forward by [amount] of bytes, I can add [amount] to this char* pointer.
I couldn't find a proper source for this, and generally only found out for sure that arithmetics on a void* isn't allowed.
From what I hacked together so far, it seems to work properly, as long as the stored structure has a constant, known size. A flexible array member in the struct breaks my current implementation. This is a shortcoming that I'm planning to fix by creating an extension: the list will hold a pointer to an array of pointers, and those pointers will give access to the actual values.
Context that might or might not be useful:
I am working on an implementation of a list data structure, and I implemented it as basically a dynamic array(expanding and shrinking whenever needed) with more interface.
I know about linked lists, and I'm also planning to implement them as a different exercise.
I defined the list like this:
typedef struct TLIST_
{
size_t size_of_value; // size [in bytes] of each record stored in the list
size_t list_capacity; // memory has been allocated for this many values(size can't be larger than this)
size_t list_size; // number of stored records
void* pointer_to_zero; // address of the content
} tlist;
// The list has a few other values for various options and operations(e.g.: disallowing it to expand automatically, displaying the content), but those four values is all that's needed for this problem.
The function for getting a pointer to a value at given index:
void* tehlist_generic_getPointerToIndex(const tlist* list__, const int index__)
{
const int capacity = (*list__).list_capacity;
if( index__ >= 0 && index__ < capacity )
{
// Move pointer forward by a given amount of bytes, through casting the void* to a char*
// 1. Can't do pointer arithmetic on void*, but can on char*
// 2. char* is defined as 1[unit or byte],
// thus moving char* forward by N, causes it to move as if we were moving through a pointer that was of size N
void* pointer_to_index = (*list__).pointer_to_zero;
const size_t bytes_forward = (*list__).size_of_value*index__;
pointer_to_index = (char*)(pointer_to_index) + ( bytes_forward );
return pointer_to_index;
}
return 0;
}
Additional information I found:
GNU C compiler offers a C language extensions that allows arithmetic on void*, by treating it as if it had size of 1 (like it was casted into char*):
https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith
This isn't allowed in ISO C, only in GNU C.
Yes, casting to char * is always legal, dereferencing that pointer is only legal within the bounds of the allocated block.
The C99 standard says in 6.3.2.3:
A pointer to void may be converted to or from a pointer to any
incomplete or object type. A pointer to any incomplete or object type
may be converted to a pointer to void and back again; the result shall
compare equal to the original pointer.
So yes it is perfectly valid as long as you do the arithmetic with the pointer of the actual type(in this case char*).

pointer to array and two dimensional array in c

struct packet_event *packet_event_p[8];
What does this mean ? Is it a pointer to an array of structure data type (struct packet_event) that has 8 elements ? And how could I make use of this pointer ?
Is it different from :
struct packet_event **packet_event_p;
If yes, how could I use this pointer ?
The first one:
struct packet_event *packet_event_p[8];
stands for 'declare packet_event_p as an array of 8 pointers to struct packet_event'. Thus, you create an array packet_event_p of 8 elements, which are pointers to the struct packet_event. Please see this link.
whereas the second one:
struct packet_event **packet_event_p;
stands for 'declare packet_event_p as pointer to pointer to struct packet_event'. Please see this link.
Hope this is helpful.
The first declaration :
struct packet_event *packet_event_p[8];
defines an array of 8 elements, each element of which is a pointer to struct packet_event . In other words, you have an array of 8 pointers, and each one points to a struct packet_event.
And how could I make use of this pointer ?
You can allocate memory for a struct packet_event and set a pointer of your array point to it, like this :
struct packet_event *ptr = malloc(sizeof(struct packet_event));
if (ptr == NULL)
printf ("Error\n");
else
packet_event_p[0] = ptr; //choose a pointer packet_event_p[0] - packet_event_p[7]
The second declaration :
struct packet_event **packet_event_p;
is different, as you declare a pointer (and not an array), named packet_event_p, which points to a pointer to struct packet_event.
If yes, how could I use this pointer ?
Allocate memory for the double pointer packet_event_p. See this link for allocating memory for double pointers.
It is true that arrays can be decayed to pointers, but they are not the same.
regarding the type it is "Array of 8 pointers to a struct of packed event"
reading the types in C usually goes in some sort of a whirlwind fashion. To properly to do, you can read this here.
Usually when you are passing this type as function argument, you will also add the size of the array, or use an external known variable to mark its length. Usually function declarations will be pointers instead of arrays type. I think even that the compiler does automatically (comments about that will be useful)
One different between those types can be seen using the sizeof operator. when applied on variable which is known to be an array type, then the result is the entire size of the array. Otherwise it will be a size of a pointer, which might be 4 byte or 8 byte (depending if its a 64/32bit machine).

Why should a struct's size reflect its alignment?

According to Wikipedia:
the last member is padded with the number of bytes required so that the total size of the structure should be a multiple of the largest alignment of any structure member
In my understanding, it means that in the following:
struct A {
char *p; // 8 bytes
char c; // 1 byte
};
struct B {
struct A a; // 16 bytes
char d; // 1 bytes
};
Struct A will have a size of 16 bytes, and struct B will have a size of 24 bytes.
The common explanation is that arrays of A should have their elements accessible at the address of the array plus the index times the size of A.
But I fail to see why that is the case. Why could we not say A has size 9 and B has size 10 (both with 8 bytes alignment), and use a special "array-storage" size when indexing into an array?
Of course, we'd still store those types in arrays in a way compatible with their alignment (using 16 bytes to store each B element). Then, we'd simply compute element addresses by taking into account their alignment, instead of considering their size alone (the compiler can do that statically).
For example, we could store 64 objects in a 1Kb bytes array of B's, instead of only 42.
In each translation unit of C, sizeof(T) is the same, regardless of the context of T. Your proposal would introduce at least two values for sizeof(T): one for arrays of T and a different one for individual objects of T. This basically introduces context-dependence into the sizeof operator. It is incompatible with how C handles pointers, arrays, and addresses of objects.
Consider the following:
void zero_A(struct A *a) { memset(a,0,sizeof(*a)); }
/* ... */
struct A single;
struct A several[3];
struct B b;
b.d = 3;
zero_A(&b.a);
zero_A(&single);
zero_A(several+1);
Under your proposal, zero_A would have to know whether the pointer it was passed pointed to struct A in an array context (where sizeof(*a) == 16) or struct A outside of an array context (where sizeof(*a) == 9). Standard C doesn't support this. If the compiler guessed wrong, or the information was lost (eg: in a round-trip through a volatile struct A *), then zero_A(&single) would invoke undefined behavior (by writing past the bounds of single), and zero_A(&b.a) would overwrite b.d and also invoke undefined behavior.
Tightly packing structs into an array is a relatively uncommon requirement, and adding context-dependence to sizeof would introduce a lot of complications to the language, its libraries, and ABIs. There are times you need to do this, and C gives you the tools you need: memcpy and unions.

Is it possible to put a C array inside itself?

In many programming languages (including JavaScript, Java, and Ruby), it's possible to put an array inside itself. Here, I'm trying to put a C integer array inside itself at its 3rd index, but I'm not sure if this is supported in the C programming language:
#include <stdio.h>
int main(void) {
int arr[] = {1, 1, 2};
arr[2] = arr; //now I'm trying to put arr into itself.
printf("%i", arr[2]); //this prints a negative number each time I run the program
printf("%i", arr[2][0]); //prog.c:7:24: error: subscripted value is neither array nor pointer nor vector
return 0;
}
Is it possible to put a C array inside itself, or is it not possible at all?
No, it's not possible for an array of int to contain itself.
There are some (likely non-portable) tricks you can play, like making one of the elements of the array be a converted pointer to the array:
int arr[10];
arr[5] = (int)arr;
but this doesn't make the array contain itself. The expression arr, since it's of array type, is implicitly converted ("decays") to a pointer to its first element in most contexts, including this one. So, assuming the conversion doesn't lose any information, you can retrieve a pointer to the first element of arr by converting arr[5] back to type int*. Note that this only gives you a pointer to arr's first element; it loses any information about the length of arr. And it's very common for an int* pointer value not to fit into an int without loss of information (on 64-bit systems, it's common for int* to be 64 bits and int to be 32 bits).
Integers, pointers, and arrays are three very different things. They are not simply interchangeable.
Recommend reading: section 6 of the comp.lang.c FAQ; it does a very good job of explaining the often confusing relationship between arrays and pointers in C.
Even in languages like Java and Ruby, an array can't actually contain itself. It can contain a reference to itself -- though the language might provide syntactic sugar that hides the fact that it's a reference. In C, such references are generally explicit.
What you can do is define a data structure that contains a pointer to an object of its own type. This is generally done with structures. For example:
struct tree_node {
int data;
struct tree_node *left;
struct tree_node *right;
};
This being C, you have to manage memory for your tree nodes explicitly, using malloc() to allocate and free() to deallocation -- or you can use an existing library that does that for you.
It actually is possible, if the length of an int on your system is equal to or greater than the length of a pointer, such that you can cast the pointer to an int to store it - and if you remember to cast it back before you try to dereference it as a pointer. Neglecting to do the latter was the cause of your error message.
Note that in such a simple scheme you will have to separately keep track of which elements are values and which are pointers. Only if you can guarantee that the length of a pointer is less than the length of an element (or that the valid range of a userspace pointer is further constrained) could you reserve some bits to indicate if an element is a literal value or a pointer.
Here's an example of how you might explicitly cast it back, based on prior knowledge that this is what would be appropriate for that element:
printf("%i", ((int *)arr[2])[0]);
To accomplish this more cleanly, you may want to make an array not of ints, but instead of unions, such that each element is a union of an int and a pointer - meaning there are two formally recognized possible views of the same memory. But you will still need a scheme to keep track of the applicable type of each element.

How is memory allocated for typedef's in structs (C) [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why isn’t sizeof for a struct equal to the sum of sizeof of each member?
When you create a struct in C, for example:
typedef struct student
{
int roll_no;
char* name;
int* pointer;
}student;
I noticed that roll_no and name are not stored contiguously in memory. How does this work? If aim is to encapsulate this data, wouldn't it be better if they were stored contiguously? How does the compiler know that these pieces of data belong together?
The compiler aligns the start of each element of a struct to match the requirements of the architecture.
This usually means alignment is on a on a word boundary, but there is no hard and fast rule.
typedef has no effect on alignment - it simply creates a "shorthand reference" to some object, maybe like a struct. You can think of typedefs as synonyms.
The name is indeed not stored together with the struct: only a pointer to it is stored. The data is usually allocated dynamically in the area outside the struct itself.
To have the name stored together with the struct you need to make it an array. The downside to this approach is that either the string must be fixed length (i.e. all structs will allocate the amount of memory sufficient for a name of max length, or you need to use a flexible array element by declaring the name[] array at the end of the struct. The downsides to this last approach is that (1) the allocation becomes a lot more complicated, (2) you cannot make an array of such structs, and (3) you can have only one flexible array in a structure.
They are stored contiguously. just that the address contained inside the char *name is somewhere else. To store contiguously in memory use a array instead of a pointer.
this is how it is stored in memory, for example, address for struct starts at 1000 (decimal).
1000 roll_no
1004 name
1008 pointer
name and pointer are pointer, so they will hold values (addresses) allocated by malloc.
s->name = malloc(100);
s->pointer = malloc(4);
In this case there is no structure padding, since all are ints (even pointers are), which means they are the size of the architecture's register sizes (usually 32 or 64 bits).
The data is stored contiguously, however there may be wholes because of optimisations and alignment onto word boundaries. The alignment depends on the processor you are running on and compiler options selected. (packing)
The compiler will calculate the offsets into your structure, so it can do the lookups into memory to fetch the elements of your structure.
Actually in the struct
struct student
{
int roll_no;
char* name;
int* pointer;
}
C does exactly what you want (besides "structure padding" but this is another story). Assuming gcc on Intel processors, struct is made of
4 bytes of int, followed by
4 bytes of char * pointer to name, followed by
4 bytes of int * pointer to pointer
The name member is a pointer to char(s), usually pointer to a string of characters, somewhere in memory. For instance
char *string = "John Doe";
int value = 255;
struct student me;
me.roll_no = 15;
me.name = string;
me.pointer = &value;
here string is somewhere in memory - as you noticed it was declared far before the structure. Say its memory location is 0x12345678, and value is at 0x20000000 and structure is at 0x22222222 so we have
0x12345678 : John Doe\0
...
0x20000000 : FF000000 // 255
...
0x22222222 : 0F0000001234567820000000
you see the structure is 0F000000 for 15, 12345678 for string address and 20000000 for value address.

Resources