I am trying to create a function that reads a .csv file and store and sort information into hash tables to later be accessed.
I wish to use the function replace from glib hash tables to change the content in the position with X key when that key already has a value stored inside. But it is instead changing the content of all positions when i just want one.
Am i using the wrong function for this or i have to approach this in a different way?
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include "../includes/estatisticas.h"
#include "../includes/Drivers.h"
#define MAX_LENGHT_RIDES 2000000
GHashTable** rides(GHashTable** arr_drivers){
FILE* rides_files = fopen("../Entrada/rides.csv", "r");
GHashTable* h_preco_medio = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
GHashTable* h_number_city = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
char* ptr;
char* city = malloc(MAX_LENGHT_RIDES);
char* str = calloc(1, MAX_LENGHT_RIDES);
fgets(str, MAX_LENGHT_RIDES, rides_files);
while (fgets(str, MAX_LENGHT_RIDES, rides_files)){
char* line = str;
char* id = strdup(strsep(&line, ";\n"));
char* date = strdup(strsep(&line, ";\n"));
char* driver = strdup(strsep(&line, ";\n"));
char* user = strdup(strsep(&line, ";\n"));
city = strdup(strsep(&line, ";\n"));
double distance = strtod(strdup(strsep(&line, ";\n")), &ptr);
char* score_user = strdup(strsep(&line, ";\n"));
char* score_driver = strdup(strsep(&line, ";\n"));
double tip = strtod(strdup(strsep(&line, ";\n\r")), &ptr);
char* comment = strdup(strsep(&line, ";\n\r"));
char* car_class = (char*) g_hash_table_lookup(arr_drivers[0], driver);
double* preco;
preco[0] = calc_preco(distance, car_class);
if(!g_hash_table_lookup(h_preco_medio, city)){
g_hash_table_insert(h_preco_medio, city, preco);
int* city_counter;
city_counter[0] = 1;
g_hash_table_insert(h_number_city, city, city_counter);
}
else{
double* novo_preco;
novo_preco[0] = ((double*) g_hash_table_lookup(h_preco_medio, city))[0] + preco[0];
g_hash_table_replace(h_preco_medio, city, novo_preco);
int* new_city_counter;
new_city_counter[0] = ((int*) g_hash_table_lookup(h_number_city, city))[0] + 1;
g_hash_table_replace(h_number_city, city, new_city_counter);
printf("%d\n", ((int*) g_hash_table_lookup(h_number_city, "Faro"))[0]);
}
}
GHashTable** arr = calloc(5, sizeof(GHashTable*));
arr[0] = h_preco_medio;
arr[1] = h_number_city;
return arr;
}
There are potentially many other issues, but you have undefined behavior at:
double* preco;
preco[0] = ...
After the invalid memory access, the behavior is undefined and anything can happen. The classical example is that demons may fly out of your nostrils, but very few implementations actually produce that result.
Note that most of the strdup calls in your code don't appear to be necessary. Since city is the key in your hash table, that is (probbably) the only value that needs to be duplicated. (I haven't looked too closely at your code; if it goes in the hash table it needs to be copied out of line. If it doesn't, it (almost certainly) doesn't need to be copied.) In any case, you certainly don't need strtod(strdup(...)), which copies the string, computes its value, and then immediatly leaks the copy. Keep the data in line only until it is going into the hash table, and only strdup the portions that are going in the hash table. And make sure everything you copy eventually gets freed. It can be tempting to allow all the frees to happen when the process closes, but adding in the explicit frees will be a good bookkeeping exercise that may expose issues in your code (and you understanding).
Related
This function is to split string based on \n and see if the row number is selected. If the row number matched, this string should be copied and used by other function:
void selectDeparment(char* departments, int selectedNum, char* selectedDepartment){
char* copyOfDepartments = malloc(strlen(departments)+1);
strcpy(copyOfDepartments,departments);
char* sav1 = NULL;
char* token = strtok_s(copyOfDepartments,"\n",&sav1);
int counter = 0;
while(token != NULL){
if(counter == selectedNum){
selectedDepartment = malloc(strlen(token)+1);
strcpy(selectedDepartment,token);
}
++counter;
token = strtok_s(NULL, "\n", &sav1);
}
}
This function is called in main like:
char* selectedDepartment;
selectDeparment(recordsPtr[0], 1, selectedDepartment);
printf(selectedDepartment);
recordsPtr[0] contains four strings with \n at the end:
aDeparment
anotherDepartment
newDepartment
otherDepartment
In C, we are encouraged to use pointer to get a value from function instead of returning a string from a function. However, the prinft in main function gives random output
I believe there is some confusion in the way you are using pointers here. Let me clarify.
In the main function, the character pointer selectedDepartment holds a certain memory in the computer. But when a function call is made to void selectDeparment(char* departments, int selectedNum, char* selectedDepartment), a new copy of selectedDepartment is created. Henceforth any changes which are made to selectedDepartment are done only at the scope of the called function and does not impact the original pointer in the main function.
Thus one clear way to solve this problem will be to pass a pointer to the character pointer defined in the main function. This will then give the correct/expected results.
Here is the modified version of the function -
void selectDeparment(char* departments, int selectedNum, char** selectedDepartment){
char* copyOfDepartments = malloc(strlen(departments)+1);
strcpy(copyOfDepartments,departments);
char* sav1 = NULL;
char* token = strtok_s(copyOfDepartments,"\n",&sav1);
int counter = 0;
while(token != NULL){
if(counter == selectedNum){
(*selectedDepartment) = malloc(strlen(token)+1);
strcpy(*selectedDepartment,token);
}
++counter;
token = strtok_s(NULL, "\n", &sav1);
}
}
And this is how it is called from the main function -
int main() {
char* recordsPtr[] = {"aDeparment\nanotherDepartment\nnewDepartment\notherDepartment"};
char* selectedDepartment;
selectDeparment(recordsPtr[0], 1, &selectedDepartment);
printf(selectedDepartment);
}
I think you are getting confused with the "A Pointer To What?" you are supposed to return. In your selectDeparment() function, if I understand what is needed, is you simply need to return a pointer to the correct department within recordsPTR. You do not need to allocate or tokenize to do that. You already have the index for the department. So simply change the return-type to char * and return departments[selectedNum];.
For example, you can whittle-down your example to:
#include <stdio.h>
char *selectDeparment (char **departments, int selectedNum){
return departments[selectedNum];
}
int main (void) {
char *selectedDepartment = NULL;
char *recordsPTR[] = { "aDepartment\n",
"anotherDepartment\n",
"newDepartment\n",
"otherDepartment\n" };
selectedDepartment = selectDeparment (recordsPTR, 1);
fputs (selectedDepartment, stdout);
}
Note: the '*' generally goes with the variable name and not the type. Why? Because:
int* a, b, c;
certainly does NOT declare three-pointers to int,
int *a, b, c;
makes clear that you have declared a single-pointer to int and two integers.
Example Use/Output
Running the example above you would have:
$ ./bin/selectedDept
anotherDepartment
You will want to add array bounds protection to ensure the index passed does not attempt to read past the array bounds. That is left to you.
If You Must Use void
If you must use a void type function, then you can pass the Address Of the pointer to the function so the function receives the original address for the pointer in main(). You can then assign the correct department to the original pointer address so the change is visible back in main(). When you pass the Address Of the pointer, it will require one additional level of indirection, e.g.
#include <stdio.h>
void selectDeparment (char **departments, int selectedNum, char **selectedDeparment) {
*selectedDeparment = departments[selectedNum];
}
int main (void) {
char *selectedDepartment = NULL;
char *recordsPTR[] = { "aDepartment\n",
"anotherDepartment\n",
"newDepartment\n",
"otherDepartment\n" };
selectDeparment (recordsPTR, 1, &selectedDepartment);
fputs (selectedDepartment, stdout);
}
(same result, same comment on adding array bounds protection)
Look this over and let me know if I filled in the missing pieces correctly. If not, just drop a comment and I'm happy to help further.
so my first question would be. Does fgets overwrite other char* values?
Otherwise, I'm not really sure how I have messed up my mallocs. Below is the code where the value is changing. First line is where the variable is being created.
data[dataIndex++] = createVariable(varName, 1, value, -1, line, NULL);
The code where the variable is being created
Variable *createVariable(char *name, int type, int val, int len, int line, char *string)
{
Variable *var = malloc(sizeof(Variable));
var->name = name;
var->setting = type;
var->num = val;
var->length = len;
var->line = line;
var->string = string;
return var;
}
What data looks like and how it was created.
Variable **data;
data = malloc(4 * sizeof(Variable *));
Forgot to add this, but below is my fgets code
if (fgets(line, MAX_LINE_LENGTH, in) == NULL)
{
break;
}
The problem is this line in your createVariable function:
var->name = name;
What this does is copy the pointer given as the first argument to the name field in the var structure; it doesn't make a (separate) copy of the data that is pointed to! So, assuming you call createVariable many times with the same variable as the first argument, then every object created will have the same address in its name field, and any modifications you make to any of them (via fgets) will change all of them.
To get round this, you need to allocate new memory for the name field, each time you call the createVariable function, then copy the string data to it. The simplest way to do this is using the strdup function:
Variable *createVariable(char *name, int type, int val, int len, int line, char *string)
{
Variable *var = malloc(sizeof(Variable));
var->name = strdup(name);
//...
var->string = strdup(string);
//...
But note, you will now need to be sure to free that memory from each object when you (eventually) delete it. Something like this:
void deleteVariable(Variable** var)
{
free((*var)->name); // free the name memory
free((*var)->string); // free the string memory
free(*var); // free the actual structure
*var = NULL; // set the pointer to NULL - to prevent multiple frees
}
EDIT: Just re-read your question, and noticed that you are making the same mistake with the string field! The same fix needs to be applied to that!
I am trying to free some memory that I allocated in one functions in another function. An example of this would be:
MusicRec * createRecord(char * title, char * artist, double fileSize, int length, char theType)
{
MusicRec * newRecord;
MusicRec * next;
newRecord = malloc(sizeof(MusicRec));
newRecord->title = malloc(sizeof(char)*(strlen(title))+1);
strcpy(newRecord->title, title);
newRecord->artist = malloc(sizeof(char)*(strlen(artist))+1);
strcpy(newRecord->artist, artist);
newRecord->sizeInKB = fileSize;
newRecord->lengthInSeconds = length;
newRecord->type = theType;
newRecord->next = NULL;
next = NULL;
return(next);
}
I have malloced memory in that function, but now i am trying to free this malloced memory in a different function such as my main function. How would i do this?
Just use the corresponding deallocation function free() Remember you cannot use already deallocated memory at all.
Some points to consider:
Better change how you allocate memory, so you can more easily change the type:
Was: newRecord = malloc(sizeof(MusicRec));
Should be: newRecord = malloc(sizeof *newRecord);
Consider defining some helper functions for things you often do. Example (this function is often actually already defined):
Was: newRecord->title = malloc(sizeof(char)*(strlen(title))+1);strcpy(newRecord->title, title);
Should be: newRecord->title = strdup(title);
Never use sizeof(char): It looks illiterate, because you are literally asking: How many char's do I need to save one char?
For cases it's not defined:
char* strdup(const char* str) {
size_t len = strlen(str) + 1;
char* ret = malloc(len);
memcpy(ret, str, len);
return ret;
}
If you have passed that variable as reference from another function then you can free that variable from that function using free() function; otherwise you can not free that variable from another function if you have passed by value.
I'm using lex to implement a scanner. I want to build a symbol table while parsing. I have two structs, SymbolEntry and SymbolTable (below). Most of the time, when I call my function for inserting a symbol (registerID, also below) I have all the information for the entry. However, when I have a constant I also want to get it's value, but that is not immediately available when I first create the entry. When I try to change the entries value later in the code, I'm invalidating the whole memory block used by that entry and the name and value are printing garbage.
Here are the two structs:
typedef struct{
char* type;
char* name;
char* value;
} SymbolEntry;
typedef struct{
SymbolEntry *entries;
size_t size;
size_t capacity;
} SymbolTable;
This is the registerID function, called when an {id} is matched. yytext contains the ID.
int registerID(char* type){
//create a new symbol entry with the specified type and name and a default value
SymbolEntry e;
e.type = type;
e.name = (char *)calloc(yyleng+1, sizeof(char));
strcpy(e.name, yytext);
e.value = "";
prevSym = insertSymbol(&table, e);
return prevSym;
}
This is the relevant code for insertSymbol(SymbolTable* st, SymbolEntry entry). pos is always the last element in the array when inserting (otherwise the entry isn't unique and pos is just returned).
st->entries[pos].name = (char *)calloc(strlen(entry.name)+1, sizeof(char));
st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char));
st->entries[pos].value = (char *)calloc(strlen(entry.value)+1, sizeof(char));
strcpy(st->entries[pos].name, entry.name);
strcpy(st->entries[pos].type, entry.type);
strcpy(st->entries[pos].value, entry.value);
Later, after the lex framework has matched the value immediately following a CONSTANTs name, this code is performed (directly in the rule for <CONSTANT_VAL>{number})
table.entries[prevSym].value = (char *)calloc(yyleng+1, sizeof(char));
strcpy(table.entries[prevSym].value, yytext);
Why does this invalidate the the SymbolEntry at this position in the array, and how can I safely change the contents of value?
EDIT:
It doesn't only happen with constants. The first two SymbolEntrys are always garbage. I'm assuming that probably means they ALL are, but the others just haven't been overwritten.
Also, it seems like subsequent calls to registerID is causing the data to get corrupted. With just 9 symbols, only the first two are garbage, with 34, it's the first 7. Adding more text to parse without variables did not cause any issues.
SOLVED
Well it turns out that I just accidentally deleted a line somewhere along the way and that's what introduced the bug. I accidentally erased my call to initSymbolTable. Thanks to chux for asking me how I initialized the table. Sorry about that.
2 potential problems.
1 - Compare
// Fields set with non-malloc'ed memory
e.type = type;
e.value = "";
// Fields set with malloc'ed memory
st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char));
st->entries[pos].value = (char *)calloc(strlen(entry.value)+1, sizeof(char));
strcpy(st->entries[pos].type, entry.type);
strcpy(st->entries[pos].value, entry.value);
Both of these set the fields to valid memory and in the second case, dynamically fill the memory. The concern is subsequent use. How does OP know to free() or realloc() the second kind and not the first. Further concern: With registerID(char* type), how do we know the value passed to type is still valid way later when that pointer is used via field type. Suggest:
e.type = strdup(type); // or the usual strlen()+1, malloc() and copy
e.value = strdup("");
2 - The type and setting of yyleng are not shown. Maybe it is not big enough as compared to strlen(e.name), etc.?
[Edit] after review, I real think e.type = type; is the problem. e.type needs its own copy of type.
Minor: Consider
// st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char));
// strcpy(st->entries[pos].type, entry.type);
size_t Length = strlen(entry.type) + 1;
st->entries[pos].type = malloc(Length);
memcpy(st->entries[pos].type, entry.type, Length);
What is the standard way to copy two structs that contain char arrays?
Here is some code:
#include stdio.h>
#include string.h>
#include stdlib.h>
typedef struct {
char* name;
char* surname;
} person;
int main(void){
person p1;
person p2;
p1.name = (char*)malloc(5);
p1.surname = (char*)malloc(5);
strcpy(p1.name, "AAAA");
strcpy(p1.surname, "BBBB");
memcpy(&p2, &p1, sizeof(person));
free(p1.name);
printf("%s\n", p2.name);
return 0;
}
The line printf("%s\n", p2.name); does not print something, because I freed the buffer.
The problem with my structs is that they are bigger than struct person. They contain hundreds of char pointers, and I have to copy every member one by one.
Is there another way to copy two structs that contain char arrays without using malloc and strcpy for every member?
You have no choice but provide a copy function yourself:
void copy_person(person *dst, const person *src)
{
dst->name = malloc(strlen(src->name) + 1);
dst->surname = malloc(strlen(src->surname) + 1);
strcpy(dst->name, src->name);
strcpy(dst->surname, src->surname);
}
which may be more elaborated than that: checking for errors, factoring the strlen + strcpy in an auxilliary function, etc.
That's what copy constructors in C++ are for.
Yes, copying struct that contain char arrays will work without any problem, but struct with char pointers (or any type of pointer for that matter) you will have to do manually.
Also note that the cast of malloc's return type is not needed in C (it is in C++) and can hide a missing prototype for malloc.
To elaborate on the answer of Alexandre C. you might want to do the malloc() as a single operation so that a free() is also simple.
This approach provides a degree of protection in that the single malloc() will either succeed or fail so that you would not have a problem of malloc() failing midway through constructing a copy. With this approach you would mix person with pointers to person that have been malloced so you might want to have two different data types something along the lines of the following in order to better mark which is which.
I have provided two alternatives for the copying with one using C Standard library functions strcpy() and strlen() and the other using a simple function that does a straight copy and returns a pointer to where it left off in the destination buffer.
I have not tried to compile this example so there may be problems with it.
There is one possible concern with this approach. Since the individual strings are not malloced you may run into a problem if you are moving the individual strings around using their pointers with the idea that each of the individual strings is its own malloced area of memory. This approach assumes the entire object is wanted or none of it is wanted.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char* name;
char* surname;
char* address1;
} person, *personptr;
// copy a string to destination string return pointer after end of destination string
char * StrCpyRetEnd (char *pDest, char *pSrc)
{
while (*pDest++ = *pSrc++);
return pDest;
}
personptr DeepCopyPerson (person *pSrc)
{
personptr pDest = 0;
unsigned int iTotalSize = sizeof(person);
iTotalSize += (strlen(pSrc->name) + 1) * sizeof(char);
iTotalSize += (strlen(pSrc->surname) + 1) * sizeof(char);
iTotalSize += (strlen(pSrc->address1) + 1) * sizeof(char);
pDest = malloc(iTotalSize);
if (pDest) {
#if 1
// alternative one without a helper function
pDest->name = (char *)(pDest + 1); strcpy (pDest->name, pSrc->name);
pDest->surname = pDest->name + strlen(pDest->name) + 1; strcpy (pDest->surname, pSrc->surname);
pDest->address1 = pDest->surname + strlen(pDest->surname) + 1; strcpy (pDest->address1, pSrc->address1);
#else
// alternative two using StrCpyRetEnd () function
pDest->name = (char *)(pDest + 1);
pDest->surname = StrCpyRetEnd (pDest->name, pSrc->name);
pDest->address1 = StrCpyRetEnd (pDest->surname, pSrc->surname);
strcpy (pDest->address1, pSrc->address1);
#endif
}
return pDest;
}
int main(void){
person p1; // programmer managed person with separate mallocs
personptr p2; // created using ClonePerson()
p1.name = malloc(5);
p1.surname = malloc(5);
p1.address1 = malloc(10);
strcpy(p1.name,"AAAA");
strcpy(p1.surname,"BBBB");
strcpy(p1.address1,"address1");
p2 = DeepCopyPerson (&p1);
free(p1.name);
printf("%s\n", p2->name);
free (p2); // frees p2 and all of the memory used by p2
return 0;
}
You have to allocate memory to any pointer if you want to do a copy. However you can always make a pointer point to already allocated memory. For example, you can do the following:
p2.name = p1.name (p1.name is already allocated memory)
This is dangerous as there are more than one reference to the same memory location. If you free either p1.name or p2.name, it results in a dangerous situation.
In order to copy the entire content you have to allocate memory to the pointers of the struct p2.
p2.name = <allocate memory>
Copy individual struct members instead of a memcpy of the entire struct
This is because memory is not allocated in a contiguous manner. Also sizeof(struct) will give you size of the members of the struct and not the memory allocated to it.
For example sizeof(p2) = 8 = sizeof(p1)= sizeof(person) even after allocating memory to members of p1.
It would be a different case had the members been char arrays.
A bit out-of-the-box thinking:
Since the structure of your struct is static, you could write a small utility program or script to generate the copy code for you.
Take the source-code of your struct definition as input, and then devise a set of rules to generate the copying code.
This is quickshot, and I don't know if it were faster to just write the copy-code manually - but at least it is a more interesting problem.