typedef struct {
int num;
char arr[64];
} A;
typedef struct {
int num;
char arr[];
} B;
I declared A* a; and then put some data into it. Now I want to cast it to a B*.
A* a;
a->num = 1;
strcpy(a->arr, "Hi");
B* b = (B*)a;
Is this right?
I get a segmentation fault sometimes (not always), and I wonder if this could be the cause of the problem.
I got a segmentation fault even though I didn't try to access to char arr[] after casting.
This defines a pointer variable
A* a;
There is nothing it is cleanly pointing to, the pointer is non-initialised.
This accesses whatever it is pointing to
a->num = 1;
strcpy(a->arr, "Hi");
Without allocating anything to the pointer beforehand (by e.g. using malloc()) this is asking for segfaults as one possible consequence of the undefined behaviour it invokes.
This is an addendum to Yunnosch's answer, which identifies the problem correctly. Let's assume you do it correctly and either write just
A a;
which gives you an object of automatic storage duration when declared inside a function, or you dynamically allocated an instance of A like this:
A *a = malloc(sizeof *a);
if (!a) return -1; // or whatever else to do in case of allocation error
Then, the next thing is your cast:
B* b = (B*)a;
This is not correct, types A and B are not compatible. Here, it will probably work in practice because the struct members are compatible, but beware that strange things can happen because the compiler is allowed to assume a and b point to different objects because their types are not compatible. For more information, read on the topic of what's commonly called the strict aliasing rule.
You should also know that an incomplete array type (without a size) is only allowed as the very last member of a struct. With a definition like yours:
typedef struct {
int num;
char arr[];
} B;
the member arr is allowed to have any size, but it's your responsibility to allocate it correctly. The size of B (sizeof(B)) doesn't include this member. So if you just write
B b;
you can't store anything in b.arr, it has a size of 0. This last member is called a flexible array member and can only be used correctly with dynamic allocation, adding the size manually, like this:
B *b = malloc(sizeof *b + 64);
This gives you an instance *b with an arr of size 64. If the array doesn't have the type char, you must multiply manually with the size of your member type -- it's not necessary for char because sizeof(char) is by definition 1. So if you change the type of your array to something different, e.g. int, you'd write this to allocate it with 64 elements:
B *b = malloc(sizeof *b + 64 * sizeof *(b->arr));
It appears that you are confusing two different topics. In C99/C11 char arr[]; as the last member of a structure is a Flexible Array Member (FAM) and it allows you to allocate for the structure itself and N number of elements for the flexible array. However -- you must allocate storage for it. The FAM provides the benefit of allowing one-allocation and one-free where there would normally be two required. (In C89 a similar implementation went by the name struct hack, but it was slightly different).
For example, B *b = malloc (sizeof *b + 64 * sizeof *b->arr); would allocate storage for b plus 64-characters of storage for b->arr. You could then copy the members of a to b using the proper '.' and '->' syntax.
A short example can illustrate:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NCHAR 64 /* if you need a constant, #define one (or more) */
typedef struct {
int num;
char arr[NCHAR];
} A;
typedef struct {
int num;
char arr[]; /* flexible array member */
} B;
int main (void) {
A a = { 1, "Hi" };
B *b = malloc (sizeof *b + NCHAR * sizeof *b->arr);
if (!b) {
perror ("malloc-b");
return 1;
}
b->num = a.num;
strcpy (b->arr, a.arr);
printf ("b->num: %d\nb->arr: %s\n", b->num, b->arr);
free (b);
return 0;
}
Example Use/Output
$ ./bin/struct_fam
b->num: 1
b->arr: Hi
Look things over and let me know if that helps clear things up. Also let me know if you were asking something different. It is a little unclear exactly where you confusion lies.
Related
I have the following struct:
struct Map {
void* arr; // includes pointers to certain blocks of memory
int mem_block_count;
};
The void* arr holds pointers to certain cells in memory. Each cell holds a void* pointer to another cell in memory (as a linked list) a char* string, and a value with its own size.
You should be able to grab one of these pointers to a cell by doing arr[i] where i is an index - is this right?
I am trying to access the first pointer to one of these cells, which is probably arr[0]. Then, I want to get access to the pointer to the next cell in memory. But this is of void type. So how do I get at it? For getting access to the char*, I just move forward in memory, and then do a strcpy. But how do I get access/deref the next pointer?
EDIT: I also thought about casting the void pointer to an int, but I'm not sure I would get the right value. Something like:
int *next_pointer;
next_pointer = (int*) map->arr[i]
But is this not preserving the pointer to the pointer when I cast this as an int? How do I dereference a pointer to a pointer correctly?
EDIT - Couldn't I also, because it is a linked list of pointers, also do something like - map->arr + index * sizeof(void*) to get to the start of a given cell?
You can't use array indexing on a void pointer, as it really just a generic pointer without a type. And if there's no type then there's no way of adding the correct offset to the base memory address. You have to cast it to the correct structure before using array indexing:
((struct some_structure *) arr)[1]
You need pointers to pointers.
#include <stdio.h>
#include <stdlib.h>
struct Map {
void **arr; // includes pointers to certain blocks of memory
int mem_block_count;
};
int main(void) {
struct Map map = {0};
int a1[100];
double a2[100];
char a3[100];
map.arr = malloc(3 * sizeof *map.arr);
if (!map.arr) /* error */;
a1[42] = 42;
a2[42] = 42;
a3[42] = 42;
map.mem_block_count = 3;
map.arr[0] = a1;
map.arr[1] = a2;
map.arr[2] = a3;
printf("%d %f %c\n", ((int *)(map.arr[0]))[42],
((double *)(map.arr[1]))[42],
((char *)(map.arr[2]))[42]);
free(map.arr);
return 0;
}
struct xyz {
int a;
int b;
char c[0];
};
struct xyz x1;
printf("Size of structure is %d",sizeof(x1));
Output: 8
why isn't the size of structure 9 bytes? Is it because the character array declared is of size 0?
Zero-length arrays are not in the standard C, but they are allowed by many compilers.
The idea is that they must be placed as the very last field in a struct, but they don't occupy any bytes. The struct works as a header for the array that is placed just next to it in memory.
For example:
struct Hdr
{
int a, b, c;
struct Foo foos[0]
};
struct Hdr *buffer = malloc(sizeof(struct Hdr) + 10*sizeof(Foo));
buffer->a = ...;
buffer->foos[0] = ...;
buffer->foos[9] = ...;
The standard way to do that is to create an array of size 1 and then substracting that 1 from the length of the array. But even that technique is controversial...
For more details and the similar flexible array member see this document.
Your array of characters has a length of 0 and hence the size of c is 0 bytes. Therefore when your compiler allocated a block of memory for that structure it only considers both integers and since you are on a 32-bit environment (assuming so from your result) the size of the structure is 8 bytes.
Remark: You can still access the field c without any compiler warnings (compiled with gcc) however it will be some garbage value.
An array of length 0 is actually not permitted in standard C, but apparently your compiler supports it as an extension.
It's one way of implementing the so-called "struct hack", explained in question 2.6 of the comp.lang.c FAQ.
Because C implementations typically don't do bounds checking for arrays, a zero-element array (or in a more portable variant, a one-element array) gives you a base address for an array of arbitrary size. You have to allocate, typically using malloc, enough memory for the enclosing struct so that there's room for as many array elements as you need:
struct xyz *ptr = malloc(sizeof *ptr + COUNT * sizeof (char));
C99 added a new feature, "flexible array members", that does the same thing without specifying a fake array size:
struct xyz {
int a;
int b;
char c[];
};
In this case:
int a;//4
int b;//4
char c[0] ; 0
So it is 8.
And
The sizeof never return 9 in you struct even if you give a size to char c[];
int a;//4 byte
int b;//4 byte
char c[1];// one byte but it should alignment with other.
just in this way:
^^^^
^^^^
^~~~ //for alignment
So, sizeof return 12 not 9
Here is the piece of codes where I don't understand
#include "malloc.h"
/*some a type A and type for pointers to A*/
typedef struct a
{
unsigned long x;
} A, *PA;
/*some a type B and type for pointers to B*/
typedef struct b
{
unsigned char length;
/*array of pointers of type A variables*/
PA * x;
} B, *PB;
void test(unsigned char length, PB b)
{
/*we can set length in B correctly*/
b->length=length;
/*we can also allocate memory for the array of pointers*/
b->x=(PA *)malloc(length*sizeof(PA));
/*but we can't set pointers in x*/
while(length!=0)
b->x[length--]=0; /*it just would not work*/
}
int main()
{
B b;
test(4, &b);
return 0;
}
Can anyone elaborate conceptually to me why we can't set pointers in array x in test()?
On the last line of test() you are initializing the location off the end of your array. If your length is 4, then your array is 4 pointers long. b->x[4] is the 5th element of the array, as the 1st is b->x[0]. You need to change your while loop to iterate over values from 0 to length - 1.
If you want to set to null every PA in b->x, then writing --length instead of length-- should do the job.
Obviously trying to figure out where the -- belongs is confusing. You better write:
unsigned i;
for (i = 0; i < length; i++)
b->x[i] = 0;
But in fact, in this case, you could simply use:
memset(b->x, 0, length*sizeof(PA));
Your structure is more complicated by one level of dynamic memory allocation than is usually necessary. You have:
typedef struct a
{
unsigned long x;
...and other members...
} A, *PA;
typedef struct b
{
unsigned char length;
PA * x;
} B, *PB;
The last member of B is a struct a **, which might be needed, but seldom is. You should probably simplify everything by using:
typedef struct a
{
unsigned long x;
} A;
typedef struct b
{
unsigned length;
A *array;
} B;
This rewrite reflects a personal prejudice against typedefs for pointers (so I eliminated PA and PB). I changed the type of length in B to unsigned from unsigned char; using unsigned char saves on space in the design shown, though it might conceivably save space if you kept track of the allocated length separately from the length in use (but even then, I'd probably use unsigned short rather than unsigned char).
And, most importantly, it changes the type of the array so you don't have a separate pointer for each element because the array contains the elements themselves. Now, occasionally, you really do need to handle arrays of pointers. But it is relatively unusual and it definitely complicates the memory management.
The code in your test() function simplifies:
void init_b(unsigned char length, B *b)
{
b->length = length;
b->x = (A *)malloc(length*sizeof(*b->x));
for (int i = 0; i < length; i++)
b->x[i] = 0;
}
int main()
{
B b;
init_b(4, &b);
return 0;
}
Using an idiomatic for loop avoids stepping out of bounds (one of the problems in the original code). The initialization loop for the allocated memory could perhaps be replaced with a memset() operation, or you could use calloc() instead of malloc().
Your original code was setting the pointers in the array of pointers to null; you could not then access any data because there was no data; you had not allocated the space for the actual struct a values, just space for an array of pointers to such values.
Of course, the code should either check whether memory allocation failed or use a cover function for the memory allocator that guarantees never to return if memory allocation fails. It is not safe to assume memory allocation will succeed without a check somewhere. Cover functions for the allocators often go by names such as xmalloc() or emalloc().
Someone else pointed out that malloc.h is non-standard. If you are using the tuning facilities it provides, or the reporting facilities it provides, then malloc.h is fine (but it is not available everywhere so it does limit the portability of your code). However, most people most of the time should just forget about malloc.h and use #include <stdlib.h> instead; using malloc.h is a sign of thinking from the days before the C89 standard, when there was no header that declared malloc() et al, and that is a long time ago.
See also Freeing 2D array of stack; the code there was isomorphic with this code (are you in the same class?). And I recommended and illustrated the same simplification there.
I just added a printf in main to test b.length and b.x[] values and everything's work.
Just added it like that printf("%d, %d %d %d %d", b.length, b.x[0], b.x[1], b.x[2], b.x[3]); before the return.
It gaves 4, 0, 0, 0, 0 which is I think what you expect no? Or it is an algorithmic error
I assume you are trying to zero all of the unsigned longs inside the array of A's pointed to within B.
Is there a precedence issue with the -> and [] operators here?
Try:
(b->x)[length--] = 0;
And maybe change
typedef struct a
{
unsigned long x;
} A, *PA;
to
typedef struct a
{
unsigned long x;
} A;
typedef A * PA;
etc
Hi I'm working with C and I have a question about assigning pointers.
struct foo
{
int _bar;
char * _car[SOME_NUMBER]; // this is meant to be an array of char * so that it can hold pointers to names of cars
}
int foofunc (void * arg)
{
int bar;
char * car[SOME_NUMBER];
struct foo * thing = (struct foo *) arg;
bar = thing->_bar; // this works fine
car = thing->_car; // this gives compiler errors of incompatible types in assignment
}
car and _car have same declaration so why am I getting an error about incompatible types? My guess is that it has something to do with them being pointers (because they are pointers to arrays of char *, right?) but I don't see why that is a problem.
when i declared char * car; instead of char * car[MAXINT]; it compiles fine. but I don't see how that would be useful to me later when I need to access certain info using index, it would be very annoying to access that info later. in fact, I'm not even sure if I am going about the right way, maybe there is a better way to store a bunch of strings instead of using array of char *?
EDIT: I didn't mean to use INT_MAX (maximum value of int), it's just some other int, which is about 20.
car and _car are both arrays, and you cannot assign arrays in C (except when the array is embedded in a structure (or union) and you do a structure assignment).
They are also arrays of pointers to char, rather than pointers to arrays of char. What you have written in the code is probably what you want - you could store pointers to up to MAXINT names in the array. However, you should describe the type correctly - as an array of pointers to char or char pointers.
A pointer to an array of characters would look like:
char (*car)[MAXINT];
And a point to an array of character pointers (thanks, Brian) would look like:
char *(*car)[MAXINT];
Be careful of MAXINT; that could be a very large array (on Linux, <values.h> defines MAXINT as INT_MAX, which is at least 231-1).
The code looks like:
struct foo
{
int _bar;
char * _car[MAXINT];
}
int foofunc (void * arg)
{
int bar;
char * car[MAXINT];
struct foo thing = (struct foo *) arg;
bar = arg->_bar; // this works fine
car = arg->_car; // this gives compiler errors of incompatible types in assignment
}
Neither the assignment to bar nor car should compile at all - arg is a void *. You presumably meant to use thing in some shape or form. As Brian noted, there are problems there, too:
You either want:
int foofunc(void *arg)
{
int bar;
char *car[MAXINT];
struct foo thing = *(struct foo *)arg;
bar = thing._bar; // this works fine
car = thing._car; // this is still an array assignment
...other code using bar and car...
}
Or you want:
int foofunc(void *arg)
{
int bar;
char *car[MAXINT];
struct foo *thing = (struct foo *) arg;
bar = thing->_bar; // this works fine
car = thing->_car; // this is still an array assignment
...other code using bar and car...
}
Or, indeed:
int foofunc(void *arg)
{
struct foo *thing = (struct foo *) arg;
int bar = thing->_bar; // this works fine
char *car[MAXINT] = thing->_car; // this is still an array assignment
...other code using bar and car...
}
Finally, dealing with the array assignment, in C you can reasonably use memmove() to do this:
int foofunc(void *arg)
{
struct foo *thing = (struct foo *) arg;
int bar = thing->_bar; // this works fine
char *car[MAXINT];
memmove(car, thing->_car, sizeof(car));
...other code using bar and car...
}
The similar function memcpy() does not have reliable semantics if the areas to be copied overlap, whereas memmove() does; it is simpler to always use memmove() because it always works correctly. In C++, you need to be cautious about using memmove() (or memcpy()). In this code, it would be safe enough, but understanding why is non-trivial.
You do need to be aware that you are just copying pointers here - you are not copying the strings that the pointers point at. If something else changes those strings, it affects both the values seen via car and the variable in the calling code.
One last point - for now: are you sure you need the argument to the function as a void *? It opens up the code to all sorts of abuse which can be prevented if the function is declared to take a 'struct foo *' instead (or even a 'const struct foo *').
You are creating a new array of size MAXINT. I think you want to create a pointer to an array of size MAXINT.
Creating a pointer to an array of char*'s:
The following is an array of size MAXINT to char* elements:
char * car[MAXINT];
The following is a pointer to: an array of size MAXINT to char* elements:
char* (*car)[MAXINT];
the following is how you set a pointer to: an array of size MAXINT to char* elements:
char* (*car)[MAXINT];
car = &arg->_car;
Other syntax errors in the question:
You need to have a semicolon after your struct definition.
You should be using foo* not foo. So it should be:
struct foo* thing = (struct foo *) arg;
You should be using thing not arg:
bar = thing->_bar;
car = thing->_car;
You can't assign to an array the way you're doing. You can do an element-wise copy.
for(int i = 0; i < MAXINT; i++)
{
car[i] = (arg->_car)[i]
}
Note that if if the strings aren't constant, you may need to use strcpy.
Array notation in C is legitimately confusing; your code doesn't mean what you think it means.
arg->_car means "the address of the array _car". Similarly, car means "the address of the array car". If you're trying to copy the contents of _car to car, then this will do it:
memcpy(car, _car, MAXINT);
But your real question, I think, is "what's the best way to store a list of strings?" This answer is: a dynamic list (one that grows automatically as you add items).
You'd declare it like this:
#define CARSIZE 65
int numCars = 0;
char **car; /* a list of addresses, each one will point to a string */
To add a car:
char *newCar = malloc(CARSIZE); /* make room */
strncpy(newCar, "Mercedes", CARSIZE); /* newCar has the address of the string */
car[numCars++] = newCar; /* store it */
To list the cars:
int n;
for (n = 0; n < numCars; ++n)
printf("%s\n", car[n]);
To remove the car at position n:
free(car[n]); /* release the memory */
/* condense the list of pointers */
for ( ; n < numCars - 1; ++n)
car[n] = car[n+1];
This is completely routine in C. NOTE: The above is off the top of my head and not copied from a working program, so I can't promise all the * are in the right place. I suspect this is a homework assignment, so I don't want to give you everything...
#define STRMAX 50
struct Person {
char sName[STRMAX];
int iAge;
};
typedef struct Person PERSON;
int main() {
PERSON *personen[1];
personen[0]->sName = "Pieter";
personen[0]->iAge = 18;
return 0;
}
This code generates an error on personen[0]->sName = "Pieter"; saying incompatible types in assignment. Why?
You don't want an array of pointers. Try
PERSON personen[1];
And like others have said, use the strcpy function!
Don't try to assign arrays. Use strcpy to copy the string from one array to the other.
...sName is an array of chars while "Pieter" is a const char*. You cannot assign the latter to the former. The compiler is always right :)
Change
PERSON *personen[1];
to
PERSON personen[1];
and use strcpy to copy the string.
strcpy(personen[0]->sName,"Pieter");
I agree with the above but I figured it was also important to include the "why"
int a; // is an integer
int *b; // pointer to an integer must be malloced (to have an array)
int c[]; // pointer to an integer must also be malloced (to have an array)
int d[5]; // pointer to an integer bu now it is initialized to an array of integers
to get b and c from simple pointers and give them memory to match d use the following to give them memory space
b = (int *) malloc(sizeof(int)*5);
where it casts the pointer returned from malloc to an int pointer, and creates a memory block of 5 times the size of an integer (thus it will hold 5 integers like d)