Clear array of structs in Rust [closed] - c

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I'm researching the possibility of porting a C program over to Rust.
Is it possible to duplicate this C code in Rust?
struct myStruct {
int var1;
int var2;
char var3[32];
int var4;
}
int main() {
struct myStruct myArray[1000];
bzero((char*) myArray,sizeof(myArray)); // clear entire array
myArray[0].var1 = 42;
sprintf(myArray[0].var3, "Hello World!");
/* other code here */
}
I've tried various methods and all come up with compile errors.

As your struct is trivially copyable and only contains types whose default value would be 0, you can simply derive Default and use an array literal:
#[derive(Copy, Clone, Default)]
struct MyStruct {
var1: i64,
var2: [u8; 32],
var3: i64,
var4: i64,
}
fn main() {
let array = [MyStruct::default(); 1000];
}
A structure that is 0-initializable with bzero is most likely always going to be Copy so you can use an array literal.
Note however that this is very likely going to be unidiomatic in Rust, where using Vec would probably be considered better, as explained in bk2204's answer.

Instead of allocating a large array and zeroing items, it may be better to use something like a Vec and insert items into it as you create them. Rust doesn't generally use the zero-initialized structure philosophy, so you'll be able to create items as you need them, and you'll be guaranteed that only valid items are stored in your structure. While it's common in C to stuff uninitialized or partially initialized data into a data structure, Rust prefers to have only fully initialized, valid data, which helps preserve safety guarantees.
You may want to have your structure have a constructor to ensure it's fully initialized, plus accessors. Or, if you aren't exposing the structure to other code, you can just manually initialize it.
If you know well how many items you need to allocate up front, you can use Vec::with_capacity to perform the allocation up front. This can be helpful even if your estimate is a little too low, since the structure can expand at runtime, just less efficiently. Depending on your allocation behavior, a VecDeque could be beneficial instead, but with the downside that you can't convert it into a slice.
If your data structure is more like a hash map or a set, whether sorted or not, then there are collections under std::collections which will likely meet your needs better.

Related

C function for converting arbitrary structure from Host to Network byte order? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have created a function my_hton() to convert data in host byte order to network byte order. It converts object of any arbitrary structure. If it is correct, why does C has functions like htons() and htonl() which converts only 2 and 4 bytes respectively, instead of having one function for all data types, or am I missing something?
void my_hton(char *buffer, char *p, size_t i){
if( is_little_endian() ){
while(i > 0){
*buffer = p[i-1];
buffer++;
i--;
}
}
}
struct demo{
int a;
char b;
char str[100];
float f;
double d;
int *ptr;
};
int main() {
char buffer[10000] = "";
struct demo object;
/*
* object initialization
*/
my_hton(buffer, (char*) &object, sizeof(object));
return 0;
}
What you have done in your code is flipped the entire structure byte wise, which would cause your individual members to be garbled.
A better question is why would you want to convert the endian ness of an entire structure?
It makes sense to change the endian ness of individual integer type fields, but that needs the information about the fields and hence you cannot have a generic function.
On the other hand if your structure has fixed size elements with equal padding, then you can write a generic function which can convert the endian-ness of each field. But I believe most structs made for network are packed and such cases would be very rare.
You can't do that in general (because structure fields have padding and alignment in addition of endianness for scalars), notably because C has no type introspection or reflection facilities. Also, it is unclear what should be done for pointers or unions or flexible array members in general.
Read more about serialization.
You might consider customizing some C compiler (e.g. extending GCC with MELT or your own plugin) to assist you in that serialization task. I don't think it is worth the effort.
However, some frameworks are adding such facilities. Look for examples into GTK Gobject introspection. Also look into C code generators like
RPCGEN or SWIG. Consider binary formats like XDR, SMILE, ASN1, etc.
In many cases, it is more convenient (even if slightly slower, but the bottleneck is often the network or the disk, not the CPU, so you won't even notice in most cases) to use some textual format like JSON, YAML, XML, .... because text protocols are very common and much easier to debug. You'll find many libraries to help you using these formats.

Why would C have "fake arrays"? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I'm reading The Unix haters handbook and in chapter 9 there's something I don't really understand:
C doesn’t really have arrays either. It has something that looks like an array
but is really a pointer to a memory location.
I can't really imagine any way to store an array in memory other than using pointers to index memory locations. How C implements "fake" arrays, anyways? Is there any veracity on this claim?
I think the author’s point is that C arrays are really just a thin veneer on pointer arithmetic. The subscript operator is defined simply as a[b] == *(a + b), so you can easily say 5[a] instead of a[5] and do other horrible things like access the array past the last index.
Comparing to that, a “true array” would be one that knows its own size, doesn’t let you do pointer arithmetic, access past the last index without an error, or access its contents using a different item type. In other words, a “true array” is a tight abstraction that doesn’t tie you to a single representation – it could be a linked list instead, for example.
PS. To spare myself some trouble: I don’t really have an opinion on this, I’m just explaining the quote from the book.
There is a difference between C arrays and pointers, and it can be seen by the output of sizeof() expressions. For example:
void sample1(const char * ptr)
{
/* s1 depends on pointer size of architecture */
size_t s1 = sizeof(ptr);
}
size_t sample2(const char arr[])
{
/* s2 also depends on pointer size of architecture, because arr decays to pointer */
size_t s2 = sizeof(arr);
return s2;
}
void sample3(void)
{
const char arr[3];
/* s3 = 3 * sizeof(char) = 3 */
size_t s2 = sizeof(arr);
}
void sample4(void)
{
const char arr[3];
/* s4 = output of sample2(arr) which... depends on pointer size of architecture, because arr decays to pointer */
size_t s4 = sample2(arr);
}
The sample2 and sample4 in particular is probably why people tend to conflate C arrays with C pointers, because in other languages you can simply pass arrays as an argument to a function and have it work 'just the same' as it did in the caller function. Similarly because of how C works you can pass pointers instead of arrays and this is 'valid', whereas in other languages with a clearer distinction between arrays and pointers it would not be.
You could also view the sizeof() output as a consequence of C's pass-by-value semantics (since C arrays decay to pointers).
Also, some compilers also support this C syntax:
void foo(const char arr[static 2])
{
/* arr must be **at least** 2 elements in size, cannot pass NULL */
}
The statement you quoted is factually incorrect. Arrays in C are not pointers.
The idea of implementing arrays as pointers was used in B and BCPL languages (ancestors of C), but it has not survived transition to C. At the early ages of C the "backward compatibility" with B and BCPL was considered somewhat important, which is why C arrays closely emulate behavior of B and BCPL arrays (i.e. C arrays easily "decay" to pointers). Nevertheless, C arrays are not "pointers to a memory location".
The book quote is completely bogus. This misconception is rather widespread among C newbies. But how it managed to get into a book is beyond me.
Author probably means, that arrays are constrained in ways which make them feel like 2nd class citizens from programmer point of view. For example, two functions, one is ok, another is not:
int finefunction() {
int ret = 5;
return ret;
}
int[] wtffunction() {
int ret[1] = { 5 };
return ret;
}
You can work around this a bit by wrapping arrays in structs, but it just sort of emphasizes that arrays are different, they're not like other types.
struct int1 {
int a[1];
}
int[] finefunction2() {
struct int1 ret = { { 5 } };
return ret;
}
Another effect of this is, that you can't get size of array at runtime:
int my_sizeof(int a[]) {
int size = sizeof(a);
return size;
}
int main() {
int arr[5];
// prints 20 4, not 20 20 as it would if arrays were 1st class things
printf("%d %d\n", sizeof(arr), my_sizeof(arr));
}
Another way to say what the authors says is, in C (and C++) terminology, "array" means something else than in most other languages.
So, your title question, how would a "true array" be stored in memory. Well, there is no one single kind of "true array". If you wanted true arrays in C, you have basically two options:
Use calloc to allocate buffer, and store pointer and item count here
struct intarrayref {
size_t count;
int *data;
}
This struct is basically reference to array, and you can pass it around nicely to functions etc. You will want to write functions to operate on it, such as create copy of the actual data.
Use flexible array member, and allocate whole struct with single calloc
struct intarrayobject {
size_t count;
int data[];
}
In this case, you allocate both the metadata (count), and the space for array data in one go, but the price is, you can't pass this struct around as value any more, because that would leave behind the extra data. You have to pass pointer to this struct to functions etc. So it is matter of opinion whether one would consider this a "true array" or just slightly enhanced normal C array.
Like the entire book, it's a case of trolling, specifically, the type of trolling that involves stating something almost-true but wrong to solicit angry responses about why it's wrong. C most certainly does have actual arrays/array types, as evidenced by the way pointer-to-array types (and multi-dimensional arrays) work.

Easy way to deal with free in an array [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
When I have a function that gets a pointer int *vector with a couple int values. I want to delete element number n. So I will use free() on that element. The problem I have now that there is a "hole" in my array of int values. Is there an easy way that I dont have this problem or do I really have to make a new int pinter and reorder my vector?
Given a function of this form:
void delete_element(int *vector, size_t index) {
// ...
}
The actual argument corresponding to vector is expected to be a pointer to a series of one or more (implied: index + 1 or more) contiguous ints. This could be part or all of an ordinary int array, or it could be a dynamically allocated block. If the former, then you cannot free any part of the space at all. If the latter, then you can free or reallocate the whole space, but not just the part associated with one element.
To avoid the deletion leaving a hole in your array, you need to move the later elements down, and to do that, you need to know how many elements there are in total. Therefore, you need a more informative function signature, perhaps something like this:
void delete_element(int *vector, size_t *size, size_t index) {
// ...
}
The actual deletion might involve simply using memmove() to move the later elements (overwriting the one to be deleted), and then decrementing the size. With respect to the latter, note that I suggest passing a pointer to the vector size, so that the function can modify the caller's copy.
If you want also to shrink the allocation then you need to do a bit more work (involving calling realloc(), and communicating the revised value of vector back to the caller), but note that in that case your function will not work on ordinary arrays.
There is no way to free() part of a block returned by malloc(). If you want to delete record[n], you need to copy record[n+1]...record[last] into the array.
If you really need to free() each element, you must first malloc() each element.

why we use sizeof using malloc? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
What is purpose of using sizeof using malloc in C?
Why its necessary?
I mean we can use sizeof but we already know the size(=1000 bytes) what we are allocating in memory?
I am beginner in C so. This might be a very obvious question.
DataTypes And Memory Matter
The answer is in the data types. While you know how many objects you want to allocate memory for, you may not want to go through the trouble of mentally computing their size.
So Does Maintainability
Also, what if the composition of these changes later? Then you're screwed and have to edit everything.
So that's irrelevant in your example, without context. But in the case where you want to allocate memory for more complex things (say, a struct with a number of fields), it does become quite important and useful.
Example 1 (not so important here):
char *s = malloc(100 * sizeof(char));
But hey, it's just chars, it's fine, you could have done that:
char *s = malloc(100);
Generally works. But shooting yourself in the foot, as you'll see below.
Example 2 (matters a bit already):
int *i = malloc(100 * sizeof(int));
Sure, you could have written that:
int *i = malloc(100 * 4);
That is, assuming you develop for just one architecture you know pretty well.
Example 3 (starting to matter quite a bit!):
typedef struct s_listelement{
int dataitem;
struct s_listelement *link;
} t_listelement;
t_listement *le = malloc(sizeof(t_listelement));
Now imagine that linked-list item's structure contains a bunch of other fields...
Would you want to trust sizeof(), or go have fun and do the math yourself?
Suppose you want to allocate memory for storing ints. Your initial guess will be, okay I need to have n integers and each integer requires x bytes. So space will be n*x bytes.
But actually this x depends on architecture. It maybe 16 bit, 32 bit, etc. So to make your code able to work in different environments, it is recommended to use n*sizeof(int) instead of n*x.
For example, if you need to allocate space for 10 integers:
int *p=malloc(sizeof(int)*10);
What happens if you change the size of mallocated?
You will have to 1) calculate again the new size (letting aside multiple target architectures problems, where you will have to calculate the new size in each target), 2) search for all malloc(1000), make sure it refers to mallocated (which might be not obvious) and replace with new size.
You don't have any of these 2 problems using sizeof. Thus using sizeof leads to a more maintainable and readable code.

how to initialize and use a 2d struct in c [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
So what i am trying to do is have an array of lists, here is my code:
typedef struct stackList{
List * list;
} stack;
int main(){
int x;
stack ** stackTable;
for(x=0;x<100;x++)
stackTable[x]=malloc(sizeof(stack*)*100);
}
i get a segmentation fault on the for loop, i would assume the way i am trying to use the struct is wrong. Would i rather in the defintion of the struct use List ** list;
or is there a way to use it the way i am trying to use it
You get segmentation fault because you're accessing stackTable while it is uninitialized. You can't know to what address of memory it points, and you haven't allocated an array to hold the pointers that you are dereferencing.
You need to make stackTable point to a valid array of pointers, in this case I think is convenient to make it be an array:
Stack* stackTable[100];
Now you have an array of pointers to Stack, you can initialize them.
If instead you have just temporarily an array large 100, and you need to make it grow in future, that's how dynamically allocating it:
Stack** stackTable= malloc(100*sizeof(Stack*));
Before trying too hard to play with pointers and dynamic memory I might suggest writing some basic programs using basic 2d arrays. For instance:
char array2d[10][10];
Once you're confortable inserting elements into this array, extracting elements, etc, you can apply all of the same principles to any type.

Resources