What's the difference between char [] and char * in struct? - c

There is a struct like this:
struct sdshdr {
int len;
int free;
char buf[];
};
And the result of printf ("%d\n", sizeof(struct sdshdr));is 8. If I change char buf[] to char *, the result would be 16. Why is char buf[] taking no space here(sizeof(int) is 4)? When shoud I choose char buf[] over char *buf?

The construct with the empty brackets [] is allowed as the last element of the struct. It lets you allocate additional space beyond sizeof(sdshdr) for the elements of the array, letting you embed the array data with the array itself.
Pointers, on the other hand, store the data in a separately managed segment of memory, and require an additional call to free at the end. Unlike the [] way, pointers let you have more than one variable-length array inside the same struct, and the element can be placed anywhere in the struct, not only at the end of the struct.

Taking "char[]" more generally:
char[] will actually allocate a number of characters inside the struct. (A struct with char x[17] will grow by 17 bytes and so on.) A char* will just hold a pointer.
An actual char x[] (with no size specified - and I think the same goes for size 0) at the end of the struct is a special case called a "flexible array member" and is discussed in the linked question and in the other answer.

Remember also that sizeof needs to be determined at compile time. Since char buf[] is a flexible array member it's size cannot be known at compile time, therefore will be omitted from the calculation of sizeof.
char * is a pointer to a char variable, and it's size is known so is included (however that is the size of the pointer not the array it points to).

Related

mallocing array of structs creates too small of an array

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?

Compile Error: sizeof() operator in C

I am not sure if this has been asked before. I tried my best to avoid duplicity.
I was using the sizeof() operator in C.
First I tried this:
char *name;
sizeof(name);
which returned size as 4 bytes. No issues till now.
Next time I tried this:
char name[];
sizeof(name); // I even tried name[]
which gave me a Compile error.
Anyone please explain why this occurs?
EDIT: I also tried inputting a string to *name which by far exceeded 4 bytes of length. Yet it was able to handle it properly. However the sizeof(name) still return 4 bytes. Even when the compiler has dynamically allocated enough memory to *name, it still reports occupying 4 bytes. Is this a sizeof() fault?
char name[]; at file scope is a tentative definition of an array. It has incomplete type. You do not know its size yet. You cannot do sizeof until after the definition has been completed.
Note that this has nothing to do with char *name; - arrays and pointers are different.
Re. your EDIT: you are confusing a pointer with the items being pointed to. char *name; takes up 4 bytes, and it points at another char. That is what a pointer does: it points at another object. It doesn't necessarily own what it points at. The semantics of a string is a series of char objects followed by a null terminator, and name should point at the first item of the series.
This all has nothing to do with sizeof name, which is the size of the pointer, not the size of the list of items being pointed at.
sizeof cannot be used with objects of incomplete array types.
char name[]; // name is of an incomplete type
C defines incomplete types as types that describe objects but lack
information needed to determine their sizes.
If you complete the type:
char name[];
char name[42]; // type of name is now completed
then using sizeof name would be valid.
Size of pointer to char is the space in memory required for that type of variable.
Size of an array of chars is number of chars in array. Which is undefined for non initialized array.

Dynamic Memory Allocation and multi-level arrays in C

Q6: Dynamic Memory allocation: Consider the following declaration for the multi-level array,
names:
char name_1[]= “John”;
char name_2[]= “Paul”;
char name_3[] = “Stephen”;
char *names[3]={name_1, name_2, name_3};
Create an equivalent multi-level array: dynamic_names that has all its elements and the data
pointed to by its elements on the heap.
What exactly does this even mean? seems a little broad and with no direction to put me in... Would be very awesome to help!
Thanks!
Create an equivalent multi-level array: dynamic_names that has all its elements and the data pointed to by its elements on the heap.
The ...multi-level array with all its elements in heap... : char **dynamic_names; (Only a pointer because the space will be allocated dynamically using malloc).
Now the 3 elements in the array dynamic_names i.e. ...the data pointed to by its elements... also need to be in heap, therefore, each of the char *name_1; , char *name_2; ; char *name_3; will also be allocated memory dynamically similarly using malloc.
P.S. : I have explained the problem in words. Try to figure out how to write the code for it. :)
EDIT: (After OP's Comment)
More explanation:
The multi-level array dynamic_names will point to 3 char* pointers.
Each of the three pointers name_1 and similar will point to 1 char array of different sizes.
To allocate a space of 5 chars and assign it to a char * pointer, you write:
char *ptr = malloc(5 * sizeof(char));
[Sincere Advice: Don't cast return value of malloc]
EDIT 2:
char **dynamic_names = malloc(3*sizeof(char*)); This will allocate space for 3 char* pointers, and assign the base address of the allocated space to dynamic_names.
char *name_1 = malloc(10*sizeof(char)); This will allocate space for a string/array of size 10 (including '\0'), and assign the base address of the space to name_1.
strncpy(name_1, "John", 5); This will initialize the space allocated for the first string (pointed to by name_1) with "John".
dynamic_names[0] = name_1; this will assign "the pointer to first string" as the first element of the dynamic_names array.
Now you have to allocate space for other two strings and provide their base addresses to name_2 and name_3 and then assign these pointers as second and third elements resp. to dynamic_array.

Declaring a variable-length array of fixed-length strings

I need an array of strings. The length of a string is known at compile-time and it is crucial that each string takes up this much space. The number of strings on the other hand is only known at runtime. What is the syntax for this?
char* data[STRLENGTH] is incorrect syntax. char** data mostly works but then sizeof(data[0]) is wrong -- it should be equal to STRLENGTH.
#Daniel is correct, but this code can confuse people who read it - it's not something you usually do. To make it more understandable, I suggest you do it in two steps:
typedef char fixed_string[STRLENGTH];
fixed_string *data;
char (*data)[LEN]; // where LEN is known at compile time
...
data = malloc(sizeof *data * rows); // where rows is determined at run time
...
strcpy(data[i], some_name);
...
printf("name = %s\n", data[i]);
...
free(data);
Note that data is a pointer type, not an array type (data is a pointer to a LEN-element array of char). The malloc call will dynamically allocate enough memory to hold rows arrays of length LEN. Each data[i] will be type char [LEN].
char* data[STRLENGTH]
declares an array of STRLENTGH pointers to char. To declare a pointer to array of STRLENGTH chars, use
char (*data)[STRLENGTH]

Initialization of Array inside a Structure in C

I'm trying to allow a variable length array inside a struct in a C program. Something like this:
struct result{
int column;
int row;
const char* a[var][var];
};
how do i do this?
even the following definition would do:
struct result{
int column;
int row;
const char* a[row][column];
};
plese do help...
You can't have variable size arrays in C structs.
You can have pointers to arrays which can be variable size (you need to handle the allocation of the space separately), but you are declaring arrays of pointers instead
If you want an array of pointers, try
const char (*a)[][];
(you'll need to manage the array as an array of pointers to arrays if you want both dimensions to be variable)
Just use pointers instead. You'll have to do dynamic memory allocation. Don't forget to free() the memory allocated for your array :)
P.S.: If you need a 2-dimensional array, use a pointer-to-pointer (that is, allocate memory for an array of pointers)
For single-dimension arrays you can do something like this:
struct TEST {
...
int size;
char string[];
}
where the size field indicates how many characters there are in the string array. The array has to be the last member of the struct, and you have to allocate the struct's memory dynamically. The allocated size should be sizeof(struct TEST) + size * sizeof(char) in this case.
You cannot have more than one variable size array in the struct. Multi-dimension variable-size arrays are trickier. It cannot be done unless only one dimension size is unknown, specifically that of the first dimension.
struct TEST {
...
int size;
char string[][100];
}
EDIT:
As other posters mentioned, you can have pointers to one or more arrays, at the cost of having to manage their memory areas separately from the struct.
EDIT 2:
This is part of at least the ISO C99 standard. Shamelessly copying from paragraph 6.7.2.1, sub-paragraph 16:
16 As a special case, the last element
of a structure with more than one
named member may have an incomplete
array type; this is called a flexible
array member. With two exceptions,
the flexible array member is ignored.
First, the size of the structure shall
be equal to the offset of the last
element of an otherwise identical
structure that replaces the flexible
array member with an array of
unspecified length.106)...
Use dynamic allocation with the malloc function.
In your case you should do something like:
#include <stdlib.h> /* header file for the malloc function */
void allocateResult(struct result* res, int row, int column) {
res->a = (const char*) malloc(row * column * sizeof(char));
}
Please note that sizeof(char) equals to 1 (almost all the time), but for other types you'd have to do it this way.
This solution implies to free allocated memory before the program ends. You'll have to pass the pointer in your struct to free:
void freeResult(struct result* res) {
free(res->a);
}

Resources