Using pointer to point to array of pointer that points to struct - c

I am having some trouble starting my program. I'm new to this. I have done some research and found some resources, but I have trouble applying it to the code. It is mostly based on pointers and structures.
I mainly need help with learning how to store the data in the struct, and how to initialize everything.
The program is supposed to find the frequency of characters in a file. I need to use dynamic memory allocation. And use a dynamically allocated array of pointers to store the characters and frequencies. I am supposed to use malloc() to allocate the array and realloc() to increase the size of the array to insert more elements. But I have no idea how to do this.
The program uses these functions-
• charInCFStruct:which returns the index of charfreq struct which has the char c stored in its member variable next. If none of the charfreq structs contains c then it has to return -1.
• printCFStruct: Prints the contents of all of the charfreq structs.
• freeCFStruct: Frees all of the charfreq structs and then frees the pointer
to the structs.
Down below is what I know is right so far. I thought it would be easier to start again from there. I am not asking for code exactly, just some help with the topics I need to do this, and a push in the right direction. Thank you!
#include <stdio.h>
#include <stdlib.h>/*
* struct for storing a char and the number of times it appears in a provided text */
struct charfreq
{
int count;
char next;
};
typedef struct charfreq charfreq;
/*
* Returns the index of charfreq struct which has the char c stored in its member variable next.
* If none of the charfreq structs contains c then it returns -1.
*/
int charInCFStruct(charfreq **cfarray, int size, char c){
}
/*
* Prints the contents of all of the charfreq structs.
*/
void printCFStruct(charfreq **cfarray, int size){
}
/*
* Frees all of the charfreq structs and then frees the pointer to the structs.
*/
void freeCFStruct(charfreq **cfarray, int size){
}
int main(void)
{
charfreq **cfarray;
FILE *inputfile;
char next;
int size = 10; /* used initial value of 10 but any positive number should work */
int i = 0;
int pos;
/* open file to read from */
inputfile = fopen("chars.txt", "r");
if(inputfile == NULL)
printf("chars.txt could not be opened. Check that the file is in the same directory as you are running this code. Ensure that its name is chars.txt.\n\n");
/* allocate space for pointers to char frequency structs */
cfarray = (charfreq**)malloc(size*sizeof(charfreq*));
/* read in chars until the end of file is reached */
while(fscanf(inputfile, "%c", &next) != EOF){
/* fill in code to fill structs with data being read in */
/* call to increase space after changing size */
cfarray = realloc(cfarray,size*sizeof(charfreq*));
}
/* print out char frequency structs */
printCFStruct(cfarray,i);
/* free all char frequency structs */
freeCFStruct(cfarray,i);
/* close the file we opened earlier */
fclose(inputfile);
return 0;
}

Related

How to store data in a CSV file to a structure and then return that structure

This is my first post at stack overflow, and hope someone is able to point me in the correct direction. I am writing a C funtion where my goal is to read a csv file. The data in the file is then passed to an structure array, which I then would like to return to a function call in main(), accessing the data for further use. How do I properly read and then return the complete structure array?
This function is an addon to an existing PLC program, where at the moment all system parameters is stored in retain memory. The goal is to read/write parameters to a CSV file for backup.I suspect that I am doing something wrong in the while loop, but are at this point not able to figure out what. It could also be I am not using pointers correctly. The CSV file looks like this:
2;motor nominal current;1700
3;motor nominal speed;2500.0
4;motor nominal power;1200.0
5;motor nominal voltage;690.0
6;Enable motor heating;TRUE
7;Motor heating time on;40.0
I am by the way aware that I don`t free the memory allocated in the function. This will be handled further on.
Here is the program containing the function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BSIZE 80
struct parameter{
int id;
char *name;
char *value;
};
struct parameter* readCSV(const char *file)
{
char buffer[BSIZE];
FILE *f;
char *field;
// open the CSV file
f = fopen(file,"r");
if( f == NULL)
{
printf("Unable to open file '%s'\n",file);
exit(1);
}
static struct parameter *parameters[BSIZE];
int i = 0;
// read the data
while(fgets(buffer,BSIZE,f) != NULL)
{
parameters[i] =(struct parameter*)malloc(sizeof(struct parameter));
// get id
field = strtok(buffer,";");
parameters[i]->id = atoi(field);
// get name
field = strtok(NULL,";");
parameters[i]->name = field;
// get value
field = strtok(NULL,";");
parameters[i]->value = field;
// display the result
printf("ID%d:\t%s\t%s\n",parameters[i].id, parameters[i].name, parameters[i].value);
i++;
}
//close file
fclose(f);
return *parameters;
}
int main()
{
struct parameter *parameters;
parameters = readCSV("QD_Config.csv");
printf("ID%d:\t%s\t%s\n",parameters[0]->id, parameters[0]->name, parameters[0]->value);
return(0);
}
I am able to print the contents of the file, but am not able to properly store the structure array before passing it it seems. In main(), when calling the function, I only get the last name and value in the file, but with the ID number of the first.
The problem you (probably) have is that the strtok function returns a pointer to the string you're tokenizing. It does not create a new string for you.
That means e.g.
field = strtok(NULL,";");
parameters[i]->name = field;
will make parameters[i]->name point to some character in buffer. And once the function readCSV returns the variable buffer ends its life-time and ceases to exist, leaving you with invalid pointer.
You need to allocate memory for the strings yourself and copy the data to them. This is either done by making the structure members arrays and use strcpy to copy the string to these arrays, or by using the non-standard but commonly available strdup function (which allocates memory dynamically of the heap and copies the string to it).
There's another problem related to returning your structures:
return *parameters;
is equal to
return parameters[0];
That is, you return a pointer to a single parameter structure.
If you want to return the whole array, you should do
return parameters; // Return the whole array
But note that it will decay to a pointer to its first element (i.e. &parameters[0]) which have the type struct parameter **, so you need to adjust the return type appropriately.
You also need to initialize parameters to null-pointers, or otherwise it's going to be hard to find the end of the array:
static struct parameter *parameters[BSIZE] = { NULL };
However a better solution which I rather recommend, is that you pass in the array as an argument, and return the number of elements you fill in. Then you can use an array of structure objects (instead of an array of structure pointers) and don't have to do any dynamic allocation and risk memory leaks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BSIZE 80
struct parameter{
int id;
char *name;
char *value;
struct parameter *next;//If you dont sure how many lins in csv you need this
};
typedef struct parameter parameter;
//I'm lazy too type struct
parameter* CreateNewQ_Q(){
parameter *Q_Q=(parameter*)malloc(sizeof(parameter));
Q_Q->name=NULL;//Nothing at first
Q_Q->value=NULL;//Nothing at first
Q_Q->next=NULL;//Nothing at first
return Q_Q;
}
void readCSV(const char *file,parameter *Q_Q)
{
char buffer[BSIZE];
FILE *f;
char *field;
parameter* A_A=Q_Q;
// open the CSV file
f = fopen(file,"r");
if( f == NULL)
{
printf("Unable to open file '%s'\n",file);
exit(1);
}
// read the data
while(fgets(buffer,BSIZE,f) != NULL)
{
if(A_A->next==NULL){//Next Nothing So Create after it
A_A->next=CreateNewQ_Q();
}
A_A=A_A->next;//A_A is New A_A now
// get id
field = strtok(buffer,";");
A_A->id = atoi(field);
// get name
field = strtok(NULL,";");
//Q_Q
//<--------Here alloc memory for your name because strtok not alloc new memory it just return a pointer in buffer[?]-------------->
A_A->name=(char *)malloc((sizeof(strlen(field)+1)*sizeof(char)));//+1 Becuz '\0' at end of string is necessary
//<--------Here Copy Result-------------->
strcpy(A_A->name, field);
//Q_Q
// get value
field = strtok(NULL,";");
//Q_Q
//<--------Here alloc memory for your value because strtok not alloc new memory it just return a pointer in buffer[?]-------------->
A_A->value=(char *)malloc((sizeof(strlen(field)+1)*sizeof(char)));//+1 Becuz '\0' at end of string is necessary
//<--------Here Copy Result-------------->
strcpy(A_A->value, field);
//Q_Q
// display the result
printf("ID%d:\t%s\t%s\n",A_A->id, A_A->name, A_A->value);
}
//close file
fclose(f);
}
void DeleteAllQ_Q(parameter *Q_Q){
if(Q_Q->next){
DeleteAllQ_Q(Q_Q->next);
Q_Q->next=NULL;
}else{
free(Q_Q->name);//I dont have next so i'm free
free(Q_Q->value);
free(Q_Q);
}
}
int main()
{
//memory control is important!!!!!!!!!!!!!!
parameter *parameters=CreateNewQ_Q();
readCSV("QD_Config.csv",parameters);
printf("Ok Load Done A_A\n");
for(parameter *loopQ_Q=parameters->next;loopQ_Q!=NULL;loopQ_Q=loopQ_Q->next){
printf("ID%d:\t%s\t%s\n",loopQ_Q->id, loopQ_Q->name, loopQ_Q->value);
}
DeleteAllQ_Q(parameters);//free parameters's next and next's next and....
free(parameters);//free self
return(0);
}
I spend sometime, i think this method control memory is more safe!

C Windows - Memory Mapped File - dynamic array within a shared struct

I'm trying to share a struct similar to the following example:
typedef struct {
int *a;
int b;
int c;
} example;
I'm trying to share this struct between processes, the problem that I find is that when I initialize 'a' with malloc, I won't be able to access the array from within the second process.
Is it possible to add this dynamic array to the memory mapped file?
You can have it as
typedef struct {
int b;
int c;
int asize; // size of "a" in bytes - not a number of elements
int a[0];
} example;
/* allocation of variable */
#define ASIZE (10*sizeof(int))
example * val = (example*)malloc(sizeof(example) + ASIZE);
val->asize = ASIZE;
/* accessing "a" elements */
val->a[9] = 125;
the trick is zero sized a array at the end of the structure and malloc larger then size of structure by actual size of a.
You can copy this structure to mmapped file. You should copy sizeof(example)+val->asize bytes. On the other side, just read asize and you know how many data you should read - so read sizeof(example) bytes, realloc and read additional asize bytes.

Scanning into structs

I want to ultimately insert strings from a file into elements in structs and can't get it right. Can you see what is wrong here?
int main()
{
FILE *fp;
char file_name[10] = "map7.map";
fp = fopen(file_name,"r");
int a = 1;
int *pnumberOfRows = &a;
fscanf(fp,"%d",pnumberOfRows);
typedef struct {
bool visited;
char *cityName;
} map;
map *ver = malloc(sizeof(map)*2*(*pnumberOfRows));
fscanf(fp,"%s",ver[1].cityName);
printf("%s",ver[1].cityName);
return 0;
}
It seems like you're simply missing to allocate space for the char *cityName fields, which makes you fscanf onto an unallocated pointer. You could either provide a fixed-with field, e.g.
typedef struct {
bool visited;
char cityName[81];
} map;
for a maximum length of 80 characters (i.e. excluding \0) or determine the length of the city names in the file beforehand and then allocating memory to the field using
ver[0]->cityName = (char*)malloc(sizeof(char)*(stringLength+1));
Note that sizeof(char) == 1, so feel free to leave it away, but see the answers here for more information. I left it here for the sake of being expressive about what you want to achieve.
Also, don't forget to free the memory you malloc'd at the end and also close the file descriptor after you're done (i.e. fclose(fp);).

Moving array of smaller structs into array of larger structs in C

Today I was working on a problem of moving an array of smaller structs directly into an array of larger structs (arrayNew) (essentially upgrading the smaller structs to store more information). The smaller structs needed to be read from a HDD in one single read operation into the array of new 'upgraded' larger structs, a function would be called to do the 'upgrading'. Also all the new fields in the structs that were read from the hard drive would be set to '0'.
Other more simple solutions that I tried were:
Creating a local array of the old structures (arrayOld), loading the structures from the HDD into it then simply looping through the empty array of the new structures (arrayNew) and manually moving each structs contents from arrayOld into arrayNew. (e.g. arrayNew[i].x = arrayOld[i].x; )
The problem with this is that in my case the arrays I was working with were very large and too large for the stack ( about 1mb for each array) causing a segmentation fault the instant the upgrading function was called.
Another viable solution was to create a dynamic array of the old structures (arrayDy) and load the old structures into arrayDy and then again manually moving each structs contents from arrayDy into arrayNew. (e.g. arrayNew[i].y = arrayDy[i].y; ) This addressed the issue of running out of stack memory.
After implementing the second solution. I decided to experiment and develop a solution that uses no dynamically allocated memory and loads the array of old structures from the HHD directly into the larger array of larger structs arrayNew in one read operation and manipulate the contents of arrayNew in memory to pad out the missing values that are there due to the array being bigger.
I will post my solution below in a scaled down version of what I implemented, using the following structs for my example:
typedef struct INNER_STRUCT_ {
int i_item1;
int i_item2;
char i_item3;
} INNER_STRUCT;
typedef struct SMALL_STRUCT_ {
int item1;
char item2;
INNER_STRUCT item3;
} SMALL_STRUCT;
typedef struct BIG_STRUCT_ {
int item1;
char item2;
INNER_STRUCT item3;
INNER_STRUCT item4;
} BIG_STRUCT;
Yes, this is possible - you can use union for that. C99 standard makes a special guarantee that can be used to implement your requirement:
6.5.2.3-5: One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the complete type of the union is visible.
Your structA_ and structB_ do share a common initial sequence, so creating a union and accessing the structs through it would do the trick:
union {
structA a;
structB b;
} u;
memset(&u.b, 0, sizeof(structB)); // Zero out the bigger structB
loadFromHdd(&u.a); // Load structA part into the union
// At this point, u.b is valid, with its structA portion filled in
// and structB part zeroed out.
Note that you cannot do it to an array (unless, of course, you make an array of unions). Each structA needs to be loaded individually into the union, from which it could then be read as structB.
The method I propose and used as a solution basically loads the smaller structs for the HDD ( a file in this case) into the array of new larger structs and then rearranges the block of memory so that each field can be accessed properly. The code to illustrate this is below, and is an mcve.
#include <stdio.h>
#include <string.h>
typedef struct INNER_STRUCT_ {
int i_item1;
int i_item2;
char i_item3;
} INNER_STRUCT;
typedef struct SMALL_STRUCT_ {
int item1;
char item2;
INNER_STRUCT item3;
} SMALL_STRUCT;
typedef struct BIG_STRUCT_ {
int item1;
char item2;
INNER_STRUCT item3;
INNER_STRUCT item4;
/*
Note that the big struct is exactly the same as the small
struct with one extra field - Key to this method working
is the fact that the extension to the struct is appended
at the end, in an array of the structs will be placed one
after the other in memory with no gaps*/
} BIG_STRUCT;
void printSmallStruct (SMALL_STRUCT *inStruct, int count) {
// Print everything inside given small struct
printf("\n\n Small struct %d, item1: %d \n",count,inStruct->item1);
printf(" Small struct %d, item2: %c \n",count,inStruct->item2);
printf(" Small struct %d, item3.i_item1: %d \n",count,inStruct->item3.i_item1);
printf(" Small struct %d, item3.i_item2: %d \n",count,inStruct->item3.i_item2);
printf(" Small struct %d, item3.i_item3: %c \n",count,inStruct->item3.i_item3);
}
void printBigStruct (BIG_STRUCT *inStruct, int count) {
// Print everything inside given big struct
printf("\n\n Big struct %d, item1: %d \n",count,inStruct->item1);
printf(" Big struct %d, item2: %c \n",count,inStruct->item2);
printf(" Big struct %d, item3.i_item1: %d \n",count,inStruct->item3.i_item1);
printf(" Big struct %d, item3.i_item2: %d \n",count,inStruct->item3.i_item2);
printf(" Big struct %d, item3.i_item3: %c \n",count,inStruct->item3.i_item3);
printf(" Big struct %d, item4.i_item1: %d \n",count,inStruct->item4.i_item1);
printf(" Big struct %d, item4.i_item1: %d \n",count,inStruct->item4.i_item2);
printf(" Big struct %d, item4.i_item1: %c \n",count,inStruct->item4.i_item3);
}
int main() {
SMALL_STRUCT smallStructArray[5]; // The array of small structs that we will write to a file then read
BIG_STRUCT loadedBigStructArray[5]; // The large array of structs that we will read the data from the file into
int i; // Counter that we will use
FILE *pfile; // pointer to our file stream
void *secondary_ptr; // void pointer that we will use to 'chop' memory into the size we want
/* Fill the array of structs (smallStructArray) */
for (i = 0; i < 5; i++) {
/* We fill each field with different data do we can ID that the right data is in the right fields */
smallStructArray[i].item1 = 111;
smallStructArray[i].item2 = 'S';
INNER_STRUCT* temp = &smallStructArray[i].item3;
temp->i_item1 = 777;
temp->i_item2 = 999;
temp->i_item3 = 'I';
}
/* Write the contents of smallStructArray to binary file then display it */
pfile = fopen("test.dat","wb");
if (pfile!=NULL){
for (i = 0; i < 5; i++) {
fwrite(&smallStructArray[i],sizeof(SMALL_STRUCT),1,pfile);
}
fclose(pfile);
}
else{
printf("Unable to open file!");
return 1;
}
for (i = 0; i < 5; i++) {
printSmallStruct(&smallStructArray[i],i);
}
/* Clear array of big structs using memset */
memset(&loadedBigStructArray[0],0,sizeof(loadedBigStructArray));
/* Here we read from the smallStructArray that was aved to file into the loadedBigStructArray */
pfile = fopen("test.dat","rb");
if (pfile !=NULL){
/*
He we pass fread the following: size_t fread(void *args1, size_t args2, size_t args3, FILE *args4)
args1 - a pointer to the beginning of a block of memory, in our case the beginning of the
array loadedBigStructArray.
args2 - the size of the ammout of bytes we wish to read, in our case the size of a SMALL_STRUCT,
the size one of the elments in the array saved to the file.
args3 - the ammount of elements to read, in our case five (which is the number of elements the
array saved to the file has.
args4 - a pointer to a FILE that specifies our input stream.
Essentially what fread will do here is read a block of bytes the size of the array we saved to
the file (smallStructArray) into the array in memory loadedBigStructArray from the
beggining of loadedBigStructArray. Fig 1 illustrates what this will look like in memory.
*/
fread(&loadedBigStructArray,sizeof(SMALL_STRUCT),5,pfile);
fclose(pfile);
}
else{
printf("Unable to open file!");
return 1;
}
/*
Due to the way the array on the file has been read into the array in memory, if we try
to access the data in loadedBigStructArray only the first 5 values will be valid, due to
the memory not being in the order we want. We need to re-arrange the data in loadedBigStructArray
*/
/*
Here we use a void pointer to point to the beggining of the loadedBigStructArray.
we will use this pointer to 'chop' the data loadedBigStructArray into SMALL_STRUCT
sized 'chunks' we can read from.
Due to the way pointers and arrays work in C we can cast the void pointer to any type we want
and get a chunk of memory that size begginnig from the pointer and its off set.
E.g. : int temp = ((int *)void_ptr)[i];
This example above will give us an integer 'temp' that was taken from memory beggining from position
void_ptr in memory and its offset i. ((int *)void_ptr) casts the pointer to type int and [i] dereferances
the pointer to location i.
*/
secondary_ptr = &loadedBigStructArray;
/*
Not we are going through the array backwards so that we can rearange the data with out overwriting
data in a location that has data which we havent moved yet. As the bottom end of the loadedBigStructArray
is essentially empty we can shift data down that way.
*/
for (i = 5; i > -1; i=i-1) {
SMALL_STRUCT temp = ((SMALL_STRUCT *)secondary_ptr)[i]; // dereference pointer to SMALL_STRUCT [i] inside loadedBigStructArray call it 'temp'
/*
Now that we have dereferenced a pointer a given SMALL_STRUCT inside loadedBigStructArray called 'temp'
we can use temp to move the data inside temp to its corresponding position in loadedBigStructArray
which rearragnes the data.
*/
loadedBigStructArray[i].item1 = temp.item1;
loadedBigStructArray[i].item2 = temp.item2;
loadedBigStructArray[i].item3.i_item1 = temp.item3.i_item1;
loadedBigStructArray[i].item3.i_item2 = temp.item3.i_item2;
loadedBigStructArray[i].item3.i_item3 = temp.item3.i_item3;
/* We then fill the new field to be blank */
loadedBigStructArray[i].item4.i_item1 = 0;
loadedBigStructArray[i].item4.i_item2 = 0;
loadedBigStructArray[i].item4.i_item3 = '0';
}
/* Print our new structures */
for (i = 0; i < 5; i++) {
printBigStruct(&loadedBigStructArray[i],i);
}
return 0;
}
Visualization of technique:
When fread does the single read operation of the array saved on disk into the array in memory due to it being smaller it will take up the first potion of the array in memory but the 'bottom' section could be anything, if we try to access the data in the new array with the current handles we have on the data we will either get inaccurate information or a bad piece of memory. We have to rearrange this data before we can use any of our handles on the structs in the array.

Assigning int *[10] from type void* when using shmat

I'm looking at some example code and trying to figure this out but am stuck. I'm just trying to create a buffer of 10 ints and have my shared memory pointers point to that. Can someone help me understand what this code is actually doing and where I went wrong?
int shmem_id; /* shared memory identifier */
int *shmem_ptr[BUFSIZE]; /* pointer to shared segment */
key_t key = 4455; /* a key... */
int size = 2048; /* 2k memory */
int flag = 1023; /* permissions */
char keystr[10];
sprintf (keystr, "%d", key);
shmem_id = shmget (key, size, flag); /* create a shared memory segment */
shmem_ptr = shmat (shmem_id, (void *) NULL, 1023);
In reality I want it to a buffer of 10 struct items.
typedef struct widget{
char color[10];
};
Your declaration:
int *shmem_ptr[BUFSIZE];
declares shmem_ptr to be an array of pointers to integers. You just want a pointer to integers, so it should be:
int *shmem_ptr;
If the memory points to widget structures, you can do:
typedef struct widget {
char color[10];
} widget;
widget *shmem_ptr;
You don't need to declare the length when declaring a pointer. The length is specified when the shared memory block is created, not in the program that attaches to it.

Resources