C: copying struct/array elements - c

I have a file in a known format and I want to convert it to a new format, eg.:
struct foo {
char bar[256];
};
struct old_format {
char name[128];
struct foo data[16];
};
struct new_format {
int nr;
char name[128];
struct foo data[16];
};
static struct old_format old[10];
static struct new_format new[10];
Problem: after filling 'old' with the data I don't know how to copy its content to 'new'. If I do
new[0].name = old[0].name;
new[0].data = old[0].data;
I get a compile error about assigning char * to char[128] (struct foo * to struct foo[16], respectively).
I tried a solution I found via Google for the string part:
strcpy (new[0].name, old[0].name);
new[0].data = old[0].data;
but I have no idea how to handle the struct. Seems I lack basic understanding of how to handle arrays but I don't want to learn C - I just need to complete this task.

If you don't want to learn C, you should be able to read the old file format in any language with a half-decent IO library.
To complete what you're trying to do in C, you could use memcpy.
So instead of:
new[0].data = old[0].data;
Use
memcpy(new[0].data, old[0].data, sizeof(foo) * 16);

You can also wrap the C arrays in a struct. Then copying elements will copy the array automatically.
typedef struct {
char name[100];
} name_array_t;
struct {
name_array_t name_struct;
...
} x;
struct {
name_array_t name_struct;
... other members ...
} y;
x.name_struct = y.name_struct;

(too obvious solution may be)
As we are dealing with the array, we can not do this kind of operation
new.name = old.name;
so i suppose you have to write a function
void Function (char *name , struct new_format *new );
where you need to assign charecter one by one.
Obviously you will Call like this : Function (old.name , &new)

Related

How to write after the end of the already initialized struct?

I have a struct initialized on a stack, and i want to write data in memory right after the struct and make a pointer inside a struct point to that data.
I know it is achievable on the stack/heap with uninitialized structure using malloc(sizeof(struct) + additional size) or alloca(). but can i perform initialization of a data after the struct is already initialized on the stack? and can i perform this initialization inside a initializator function?
Simple example:
struct TEST {
wchar_t* itest;
};
void init_struct(struct TEST* test) {
// point to the end of the struct
char* walk_ptr = (char*)test + sizeof(test);
test->itest = (wchar_t*)walk_ptr;
// initialize data after the struct
...
}
int main(void) {
struct TEST test;
init_struct(&test);
return 0;
}
You could do this by embedding the structure inside another structure to reserve memory for the extra data:
int main(void)
{
struct { struct TEST test; wchar_t data[NumberOfElements]; } S;
init_struct(&S.test);
…
}
However, the code in init_struct adds an incorrect size, sizeof(test), to the pointer. You likely wanted to add sizeof (struct Test), or, equivalently, sizeof *test, since you want to get past the struct TEST that test points to, not past a struct TEST * that test is.
However, even adding the correct size of the structure would not guarantee strictly conforming C code, since C implementations may insert padding between structure members. Properly we would add the offset of the data member. To do that, we nwould eed to give the structure a tag and then either make the structure definition visible to init_struct or pass the offset to init_struct. However, it is easier just to pass the address of the extra data:
void init_struct(struct TEST *test, wchar_t *data)
{
test->itest = data;
}
int main(void)
{
struct { struct TEST test; wchar_t data[NumberOfElements]; } S;
init_struct(&S.test, S.data);
…
}
Of course, a pointer can point anywhere, and there is no apparent reason the data should be immediate after the structure, so we can disconnect them:
int main(void)
{
struct TEST test;
wchar_t data[NumberOfElements];
init_struct(&test, data);
…
}

Subscripted value is neither array nor pointer nor vector at array index

(Homework question)
I'm just learning C, and I'm making a program that reads data from a file, creates routers of that data, and puts pointers to the routers in an array of size 255, but I keep getting the title error on the line where I'm trying to add them to the array
#define ARRAY_SIZE 255
struct router routers[ARRAY_SIZE] = {0};
int main(int argc, char *argv[]){
unsigned char id;
char name[32];
struct router *new_router;
if(argc == 2){
//reads file with fread
//setting id and name which prints out as expected
new_router = make_router(id, name); //initialising method that returns a router pointer
routers[new_router->id] = new_router;
//error occurs here, at [new_router->id]. Have also tried just using id
}
}
I've searched a lot of threads with the same error message, but they're all either someone who didn't declare an array, or were suggested to try it with unsigned char as index number, which is what I'm already using. Would love some insight into this.
struct router{
unsigned char id;
char name[32];
}
struct router* make_router(unsigned char id, char* name){
struct router *r = malloc(sizeof(struct router));
r->id = id;
r->name = name;
return r;
}
Assuming make_router allocates a struct dynamically, then
routers[new_router->id] = *new_router; // note *
solves the compiler error.
However, you cannot copy structs like this if they have pointer members. You say that "Router is just a basic struct with an unsigned char for id, and a char* for name" so this is the case. But with an assignment like this, you won't get a hard copy of the pointed-at data.
Pointers are not data. They do not contain data. They point at data allocated elsewhere.
So probably what you are actually looking for is an array of pointers, as suggested in another answer. If so, you have to re-write this program.
This:
struct router routers[ARRAY_SIZE] = {0};
means routers is an array of ARRAY_SIZE structures. Not pointers to structures, which is what this:
routers[new_router->id] = new_router;
is trying to assign into one of the elements.
If make_router() is dynamically allocating the memory, the fix is probably to change the array declaration into an array of pointers:
struct router * routers[ARRAY_SIZE];
^
|
way
important
EDIT: Of course, I assumed that there was an actual declaration of struct router somewhere that you just omitted. Might be a good idea to include it, just for completeness' sake.

read struct objects from a file and point to the object read using void* pointer

I have the following four structs in my program
struct SType{
int type;//struct type
};
struct S1{
};
struct S2{
};
struct S3{
};
I am saving the states of these structs in a file using the following code:
void store(struct SType s1,void *s){
//open file and stuff
//s points to either one of the last three structs
fwrite(&s1,sizeof(s1),1,file); fwrite(s, size, 1, file);
//structs are always saved in the file in pairs of SType and either one of the last three structs
}
Now when i am trying to retrieve the second struct of the pair from the file using the following code, i get segmentation fault. So how do i retreive an object of an arbitary struct type using fread()?
void read(){
void *record;
//read struct SType object from the file
//now read the second struct of the pair
fread(record,size,1,file);
}
You have to read into valid memory. void means "I don't know" and the system cannot and will not guess that value for you!!
What you have is:
void read(){
void *record;// This pointer currently is a random value - this will cause a fault when you try and copy data into it by calling:
fread(record,size,1,file);
}
It should be:
void read(){
void *record;
len = ?; // Your program needs to know this. You must know which structure it is somehow if you are to cast it later. Therefore you should know its size.
record = malloc(len); // Where len has been previously found to be AT LEAST big enough to read into
fread(record,size,1,file);
}
As you say your code is not psuedocode, then also put something in your structs so they're not empty. It would also be advisable to do something with the structure once you've read it, for example return the void * from your fread.
Hope that helps.
You read a record to uninitialized pointer, I guess you should alloc memory first.
void *record = maloc( size )
And do not forget to free ...
May I suggest you to use a Union?
Your type definitions will look like this:
struct SType{
int type;//struct type
};
struct S1{
};
struct S2{
};
struct S3{
};
union S{
S1 s1;
S2 s2;
S3 s3;
};
now read and write can be done like this:
SType stype;
S s;
fread(&stype,sizeof(stype),1,file);
size = ??? //get according to type
fread(&s,size,1,file);
// your data will be stored according to type in s.s1, s.s2 or s.s3
size = ??? //get according to type
fwrite(&stype,sizeof(stype),1,file);
fwrite(&s,size,1,file);
Next stage, is to unify the Type with the rest:
struct S{
int type;//struct type
union {
S1 s1;
S2 s2;
S3 s3;
}s;
};
/* in case you don't care about loosing file space,
you can read\write all in a single operation like this:
*/
S s;
fread(&s,sizeof(s),1,file);
// now according to the type you take s.s.s1, s.s.s2 or s.s.s3.
fwrite(&s,sizeof(s),1,file);
/* if you do care about loosing file space, you work like before */
S s;
fread(&s.type,sizeof(int),1,file);
size = ??? //get according to type
fread(&s.s,size,1,file);
// as before, you take s.s.s1, s.s.s2 or s.s.s3.
size = ??? //get according to type
fwrite(&s.type,sizeof(int),1,file);
fwrite(&s.s,size,1,file);

How to convert pointer array to char array?

I have this:
typedef struct nodebase{
char name[254];
char sex;
int clientnum;
int cellphone;
struct nodebase *next;
struct nodebase *encoding;
} clientdata;
I have added clientdata *curr[]; in seperate function. The reason why I made *curr into *curr[] instead is that this client data will be stored in a .txt file. So I came up with singly linked-list to read all the data and when the program fscanf every 5th variable, I will add 1 to clientcounter.
So, the *curr[] will be *curr[clientcounter].
Now, I need to convert this pointer array into char array named temp[clientcounter] because char array is needed to evaluate something else later in the code.
I came up with this code below:(Using Tiny C on Windows)
void loaded_data_transfer(clientdata *curr,clientdata temp[],int clientcounter)
{
clientdata temp[] = {0};
temp[clientcounter].name = curr[clientcounter]->name;
temp[clientcounter].sex = curr[clientcounter]->sex;
temp[clientcounter].clientnum = curr[clientcounter]->clientnum;
temp[clientcounter].cellphone = curr[clientcounter]->cellphone;
}
The problem is, Tiny C is giving me an error: lvalue expected at temp[clientcounter.name = ... part. Can anyone tell me what did I do wrong?
And if anyone knows a better way to keep track of the curr of clientdata by using counter and by using singly linked-list, please let me know.
You cannot assign an array to another. You should use strcpy or strncpy
strcpy(temp[clientcounter].name, curr[clientcounter]->name);
Maybe you meant to copy the entire struct:
void loaded_data_transfer(clientdata * curr, clientdata temp[], int clientcounter)
{
temp[clientcounter] = *curr; // Copy entire struct
}
It should work, because your struct doesn't any pointer members.
I am assuming you use it like this
clientdata * curr[CURR_SIZE];
clientdata temp[TEMP_SIZE];
/* init curr elements here */
loaded_data_transfer(*curr[clientcounter], temp, clientcounter);
Also, your declaration should be:
void loaded_data_transfer(clientdata *curr[],...

Pointer to struct

I am working on assignment. I started with the struct:
struct figures_struct
{
char figure_name[130];
double figure_coordinates[1000000];
};
When I read name of the figure from the file, I stored it into the struct as follows:
strcpy(figures[i].figure_name,f_name);
Now I have to modify my code and need to use dynamic memory. I did:
struct figures_struct
{
char figure_name[130];
double figure_coordinates[100000];
};
struct figures_struct *figures = malloc(size * sizeof(struct figures_struct));
Now, how do I store figure name into my struct? figures[i].figure_name does not seem to be working.
strcpy(figures[i].figure_name, f_name);
That will still work with pointers(as pointers and arrays are almost interchangeable in C)
It will work as soon as "i" is less than "size".

Resources