I'm working on a practice exercise and it seems printf() is writing over my variable somewhere. I'm working with a structure containing a pointer to an array of pointers to structures so I'm sure I've assigned something slightly wrong somewhere.
int dictionary_add(struct dictionary* d,
const char * const english,
const char * const foreign){
/* ROLE Adds a new wordPair made of strdup copies of the parameter strings
to a dictionary d
RETURNS 0 if everything went fine
PARAMETERS d the dictionary to work with
english string representing the english part of the new wordPair
foreign string representing the foreign part of the new wordPair
*/
//Determine where in the array the wordPair is going.
int location;
location=((d->size)-(d->nbwords))-1;
printf("Adding data to array location: %i\n\n",location);
//Build the wordPair
const struct wordPair newPair={english,foreign};
//Add the wordPair
d->data[0]=&newPair;
//***************This is where the problem shows up***************
printf("Added english:%s\n",d->data[0]->englishWord);
//d->data[0]=&newPair; //When uncommeted, program doesn't crash.
printf("Added english:%s\n",d->data[0]->englishWord);
d->nbwords++;
return 0;
}
How this is called from main():
const char* english=malloc(sizeof(char)*6);
const char* foreign=malloc(sizeof(char)*6);
strcpy(english,"hello");
strcpy(foreign,"holla");
Where the dictionary is created:
struct dictionary *dictionary_build(int size){
/* ROLE Allocate and initialize a new dictionary structure able to accomodate a number of
pairs of words specified by the size parameter
RETURNS Address of new dictionary, if allocation was successfull.
NULL otherwize
PARAMETERS The size of the dictionary to make
*/
struct dictionary *d=malloc(sizeof(struct dictionary));
d->size=size;
d->nbwords=0;
struct wordpair* wordPairs[size]; //create array of pointers to wordpairs
d->data=&wordPairs; //Set pointer to array of pointers to wordpairs
return d;
}
The structures:
struct wordPair {
char* englishWord;
char* foreignWord;
};
struct dictionary {
struct wordPair ** data;
int nbwords;
int size;
};
Thanks in advance for any help. And I'm not opposed to the idea that my entire design misses the point. I can change anything outside of the struct definitions and the expected parameters.
When you do this:
struct wordpair* wordPairs[size];
d->data=&wordPairs;
return d;
}
wordPairs has automatic storage, and its lifetime will end when the function returns. It's undefined behavior to attempt to refer to an object after the end of its life, yet you are retaining a pointer to it within d which you then try to dereference in dictionary_add().
Use something like d->data = malloc(size * sizeof(struct wordpair *)); or similar, instead. Don't forget to check the return from malloc() to determine whether it succeeded, and (usually) to free() everything when you're done.
Related
I am really confused with passing my struct to void pointers, I'm not sure which one can be assigned directly and which one should be memcpyed, I've tried a lot of combinations but it does not seem to work. Any help would be very appreciated!
This is my C code
struct SomeStruct {
int a;
char name[10];
};
void *randoms[10];
void transferFunction(void* data, int index) {
// This function copies data to randoms[index]
// I would like to have the whole struct's data in randoms[index]
memcpy(&randoms[index], data, sizeof(struct SomeStruct));
}
struct SomeStruct *ss = malloc(sizeof(struct SomeStruct));
ss->a = 1;
strcpy(ss->name, "abc");
transferFunction(ss, 0);
My goal is to have the randoms[index] having the struct's data as another function is going to read from it, as shown below, but I am unable to retrieve the struct data correctly, it gives me some garbage value
void readFunction() {
struct *SomeStruct ss = malloc(sizeof(struct SomeStruct));
memcpy(ss, &randoms[index], sizeof(struct SomeStruct));
printf(ss->name);
}
Does anyone knows how to solve this problem? Thank you very much!!!
You can not "copy in to a void".
A void * can contain a memory address, but does not contain any information about the size of the data at that address.
Also, it can not contain any data, only an address!
In this line:
void *randoms[10];
You create an array that can hold 10 addresses.
You never initialize this array, so it will start out all zeroes (this only works for global variables in C).
You can put the address of your structure in to the array, like so:
random[0] = (void*)ss;
However, this does not transfer any data, so if you free the original structure (ss) your data is gone, and the address in random[0] is illegal.
If you want to transfer data you need to create array of struct SomeStruct or you need to allocate another SomeStruct, store its address in random[0] then memcpy to that address.
void transferFunction(void* data, int size, int index)
{
randoms[index] = malloc(size);
if (randoms[index] != NULL) {
memcpy(randoms[index], data, size);
}
}
Your code has some problems:
struct *SomeStruct ss = ... should be struct SomeStruct *ss =.
You are not cheking the return value of malloc() (which may fail).
You are not freeing ss allocated with malloc(). You should call free() on ss.
My goal is to have the randoms[index] having the struct's data
Lev M.'s answer already answers this part.
as another function is going to read from it
Simply assign your void pointer to a SomeStruct pointer:
void readFunction(int index)
{
if (index >= 10) // Index out of range
return;
struct SomeStruct *ss = randoms[index];
printf("%s\n", ss->name);
}
Let's say I have the following struct and array of that struct:
struct Fileinfo {
int ascii[128]; //space to store counts for each ASCII character.
int lnlen; //the longest line’s length
int lnno; //the longest line’s line number.
char* filename; //the file corresponding to the struct.
};
struct Analysis fileinfo_space[8]; //space for info about 8 files
I want to have a function that will add a new struct to this array. It must take a void pointer to the position where to store the struct as an argument
int addentry(void* storagespace){
*(struct Fileinfo *)res = ??? //cast the pointer to struct pointer and put an empty struct there
(struct Fileinfo *)res->lnlen = 1; //change the lnlen value of the struct to 1
}
My questions are:
What goes in place of ??? I tried (Fileinfo){NULL,0,0,NULL} as per this Stackoverflow response. But I get `error: ‘Fileinfo’ undeclared (first use in this function)
How do I create a void pointer to the array? Is (void *)fileinfo_space correct?
I am required to use void * as the argument for the function for this assignment. It's not up to me.
Let's say you have some memory block passed as storagespace void pointer:
You have to define a constant to be able to initialize (unless you're using c++11), let's call it init. BTW your assignment value is wrong: first member is an array of int. You cannot pass NULL to it. Just zero-fill it like show below.
Then cast your void pointer into a pointer on your struct, then initialize by copying the init struct, modify at will...
int addentry(void* storagespace){
static const struct Fileinfo init = {{0},0,0,NULL};
struct Fileinfo *fi = (struct Fileinfo *)storagespace;
*fi = init; //cast the pointer to struct pointer and put an empty struct there
fi->lnlen = 1; //change the lnlen value of the struct to 1
}
I am not sure i'f i was specific and clear enough.
But ill clear the doubt.
I am trying to assign a NULL value to a pointer.
given the code :
typedef struct Date
{
int year;
int month;
}Date;
typedef struct Record
{
char name[20];
char cdate[20];
float quanitity;
int barcode;
Date date;
}Record;
and then in main :
Record *records = malloc(10 * sizeof(Record));
records[0] = NULL;
This just doesn't work, when I define a similliar array of premitive type, for example int
I can assign values, or NULL
For example for
int *avi = malloc(sizeof(int)*10);
avi[0] = 3;
avi [0] = NULL;
It works fine, i've printed the values and seen the changes.
However when I do the same for an array of pointers to struct, as defined above
I just can not assign a NULL value..
clueless.
I am using eclipse IDE.
thanks in advance.
Your problem is that records is a pointer to 10 objects. Thus, records[0] is the first object. You cannot set the object to NULL.
It only appears to work for int because you set the int to zero, not NULL.
NULL is a built in constant which has a value of 0. That's why you can assign it to primitive types such as int and char. It works for pointers due to a specific construct of the C language that tells the compiler that "0" means "point to an invalid memory address", which may not be the actual value "0".
Your assignment of NULL to a structure type doesn't work because you can't set a structure to an integer type.
Here is an example of creating an array of pointers to Record structures. Because the array contains pointers to the Record structures instead of containing the structure directly the pointers can be set to NULL - something you can't do if the array contains the Record structure directly.
#include <stdlib.h>
typedef struct Date
{
int year;
int month;
}Date;
typedef struct Record
{
char name[20];
char cdate[20];
float quanitity;
int barcode;
Date date;
}Record;
int main()
{
// We start by creating an array of 10 Record pointers.
// records is a pointer to the array we create
Record **records = malloc(10 * sizeof(Record*));
// First thing is first - did it work?
// There is no point in doing anything else if the array didn't get created
if (records != NULL) {
// The Record pointers are uninitialized
// Arrays don't do that automatically
// So we need to initialize all the pointers
// in this case we set them all to NULL
for (int i=0;i<10;i++)
records[i] = NULL;
// Later on in the program we might want to
// create one Record structure and assign it to records[5]
records[5] = malloc(sizeof(Record));
// Again, we need to check if the Record structure got created
if (records[5] != NULL) {
// Do something with this Record structure
// Fill it in, print it out, etc.
}
// Then at the end of the program
// we want to deallocate all the Record structures we created
for (int i=0;i<10;i++)
if (records[i] != NULL)
free(records[i]);
// And finally we need to deallocate the array of pointers
free(records);
}
return 0;
}
I'm sure that the answer to this is me not understanding Pointers and References properly!
So at the start of my C file I define a struct for people:
typedef struct {
char id[4];
int age;
char name[128];
} people;
Then inside of main() I create an array of 10 people structs called record.
people* record = (people*)malloc(sizeof(people)* 10);
In main() we start and then dive off into a function with
MyFunction(record);
(This function is prototyped at the beginning of the C file before main() with
int MyFunction(people *record);
Inside of MyFunction() we do various stuff, including wanting to increase the record array size so that it can hold more people structs.
I'm attempting to increase the record array size with
struct people *tmp = realloc(record, 20 * sizeof (people));
if (tmp)
{
record = tmp;
}
But this doesn't work and I get memory corruption if I attempt to use the newly added structs in the array.
As I said, I'm sure that this is due to me not understating Pointers and References properly.
Note that I can't have MyFunction() give an expanded record array as its return type because I'm already using its return int for something else (and I'm not sure I'd get that to work properly either!) - I need it to be using the main record array.
Can anyone point me in the right direction please?
int MyFunction(people **record);// MyFunction(&record);//call at main
...
struct people *tmp = realloc(*record, 20 * sizeof (people));
if (tmp)
{
*record = tmp;
}
I am a newbie in C..I am trying to make some sense of how dynamic memory allocation works in case of structures and arrays..So like for example I have a code like..
struct Person
{
int id;
char *name;
char *place;
};
struct Database
{
struct Person *data_rows;
};
I want to dynamically allocate memory for both the character arrays name and place..and the array of struct data_rows..take their size as input..So what should ideally be the order of allocations and the proper syntax for the same? Thanks.
Well, "obviously" you need to get "struct Database" filled in first:
struct Database MyDatabase;
MyDatabase.data_rows=malloc(sizeof(MyDatabase.data_rows[0])*NumberOfPeople);
Ignoring the fact that I didn't check the malloc() for failure, this will give you an array of "struct Person", all uninitialized. So, most likely, you'll want to initialize them:
int i;
for (i=0; i<NumberOfPeople; i++)
{
struct Person* MyPerson;
MyPerson=&MyDatabase.data_rows[i];
MyPerson->id=i;
MyPerson->name=malloc(...);
/* Do something to store the name in MyPerson->name */
MyPerson->place=malloc(...);
/* Do something to store the place in MyPerson->name */
}
Now, the problem here is the "..." I put on the malloc. It's easy if you use a fixed size, but then you could have just declared your struct to be something like
struct Person
{
int id;
char name[100];
char place[200];
};
Basically, I just can't tell what the length of the names should be, hence I just typed it as "...".
Also, I just guessed what the "id" might be. Using the array index is actually somewhat pointless :-)
Of course, you don't have to do it all now. You could just set the name and place pointers to NULL and fill them in later, like when you're reading the data from a file, or whatever you're planning to do. Or you could just not initialize it here at all, if you're confident that your code always "knows" which fields are initialized and which ones are not.
I would highly recommend to write a functions person_new and person_free that would take care of structure memory management:
struct Person* person_new(char *name, char* place) {
struct Person* person = malloc(sizeof(struct Person));
person->name = strdup(name);
person->place = strdup(place);
return person;
}
void person_free(struct Person* person) {
free(person->name);
free(person->place);
free(person);
}
The best thing would be to convert your structs to classes, the following works also for structs...
You define a constructor and destructor in Database and in Person as following:
struct Person
{
Person(){
name = new char[256];
place = new char[256];
};
~Person(){
delete name;
delete place;
}
int id;
char *name;
char *place;
};
struct Database
{
Database(int nPersons){
data_rows = new Person[nPersons];
};
~Database(){
delete data_rows;
};
struct Person *data_rows;
};
or you can do this without a constructor and destructor and allocate all the stuff sequentially in your code, which is a very ugly way to do this!
as:
Database myData;
myData.data_rows = new Persons[40];
for(int i=0; i < 40; i++){
myData.data_rows[i].name = new char[256];
myData.data_rows[i].place = new char[256];
}
Note that data_rows[i] is nothing more than -> *(data_rows + i) which shifts the address of the pointer i times and then dereferences it!