I'm struggling (again..) with a project in C coding.
Please help me to understand how to access a variable that was dynamically allocated, through 2D array that was also dynamically allocated.
Every attempt ends up with failure, and I can't find the right syntax...
The attempt : putting a string in the family_name pointer in the new Family allocated into **list.
scanf(" %s",&lod->list[0]->family_name);
The program:
#define _CRT_SECURE_NO_WARNINGS
//Libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Consts, globals, structs
#define MAX 10000
typedef struct person
{
char *name;
int gender; //1-female, 0-male
} Person;
typedef struct family
{
char *family_name;
Person *mother, *father; // parents' names
Person **children_list; // list of the children in this family
unsigned child_list_size; // size of child_list array
unsigned current_listChild_size;
} Family;
typedef struct listFamilys
{
Family **list;
unsigned current_listFamily_size; // current size of family
}
ListFamilys;
//main
void main()
{
ListFamilys *lod = (ListFamilys*) malloc(sizeof(ListFamilys));
if(! lod) exit(0);
lod->current_listFamily_size =0;
lod->list = (Family**)malloc(sizeof(Family*));
if (!lod->list) exit(0);
printf("Enter family name: ");
**scanf(" %s",&lod->list[0]->family_name);**
system("pause");
}
The issue here is simply a type error combined with insufficient allocation. In order for this to work you need to allocate space for some Family pointers (which you are doing, though only 1), and then an actual Family element (which you are not doing) and then allocate space for the name (which you are not doing). Basically, the code should be
lod->list = (Family**) malloc(sizeof(Family*));
lod->list[0] = (Family*) malloc(sizeof(Family));
lod->list[0]->family_name = (char*) calloc(11, 1);
where you are only doing the first line of that. My usage of calloc here is somewhat arbitrary, as is the 10 char limit. You can modify as is appropriate.
However, while this is the simplest way to get a single element up and running, this approach collapses at the large scale because of how many allocations you have to do, and deallocating memory becomes a nightmare due to how many separate allocations are made using this approach. Therefore, it is better to allocate say 4kb of space for names to a separate pointer, and then point the name field of persons and families to the relevant name rather than a separate allocation for each of their names. So on with the rest of it. Essentially, try to extract allocations rather than tunnel down with them field after field like the code above does.
Related
So I've been looking at structures, functions and pointers for days now. I just cant wrap my head around structures good enough to do what I want...
I was trying to write a function, which was originally going to receive user input (taken with fgets) as an argument. I have put that aside now, and just decided to give the function a single argument. That argument will be the name of a struct, and I'll use that name to access it's variables and print them the way I want.
typedef struct
{
int hp;
char *name;
} bare;
bare example;
void print_info(char *name);
int main()
{
example.hp = 5;
strcpy(example.name,"John");
print_info("example");
}
void print_info(char *name)
{
printf("The hp of %s is %d", (*name), (*name)->hp);
}
Whatever bloody thing I put there instead of char *name, it always ended up giving me the error "error: struct or union expected"! I tried struct bare **name and (*name)->hp/(*name).hp, char *name/**name and *&name.hp, *&name->hp, every possible solution I could think of..! i think they all turned out to be nonsense... I just cant wrap my head around pointers and structs enough to do this! A little help please? I searched high and low on function arguments, pointers and structs, yet couldn't find a solution/question like mine..
First, it's better to declare your struct this way:
typedef struct bare {
int hp;
char *name;
} bare;
Second, avoid global variable as much as you can. I don't see the point of declaring example in the global namespace since you are using it only inside main().
Third, this line has a problem:
strcpy(example.name, "John");
You are attempting to copy "John" to an uninitialized pointer (example.name) that points to some random memory address. You have to either allocate enough space using malloc() (and free it when you're done with it), or use a fixed-length array. Moreover, it's better to use strncpy() because it allows to specify the maximum number of characters to copy. This way you avoid the risk of buffer overflow.
Fourth, to avoid copying your entire struct to print_info() (in fact, any other struct to any other function), you should pass its address.
With all that said, here is how your code should be written:
#include <stdio.h>
#include <string.h>
typedef struct bare {
int hp;
char name[100]; // Make sure it has enough space, or use malloc() if you don't know how much it will hold initially
} bare;
void print_info(bare *name);
int main(void)
{
bare example; // Declare it inside main()
example.hp = 5;
strncpy(example.name, "John", sizeof example.name); // This works and is safe
print_info(&example);
}
void print_info(bare *name)
{
printf("The hp of %s is %d", name->name, name->hp);
}
Output:
The hp of John is 5
I think what you wish to do is this:
#include <stdio.h>
#include <string.h>
typedef struct {
int hp;
char *name;
} bare;
bare example;
void print_info(bare *name);
int main() {
example.hp = 5;
strcpy(example.name, "John");
print_info(&example);
}
void print_info(bare *name) {
printf("The hp of %s is %d", name->name, name->hp);
}
Or if you want to pass example by value:
#include <stdio.h>
#include <string.h>
typedef struct {
int hp;
char *name;
} bare;
bare example;
void print_info(bare name);
int main() {
example.hp = 5;
strcpy(example.name, "John");
print_info(example);
}
void print_info(bare name) {
printf("The hp of %s is %d", name.name, name.hp);
}
Why did your code not work?
print_info had an incorrect argument data type. What you wanted was to pass an object of bare or perhaps a pointer to an object of bare, but you were instead passing a variable of type char *.
The arrow operator is used on pointers. Maybe take a look at Arrow operator (->) usage in C.
You wanted to pass in a string typed in by the user.
I was trying to write a function, which was originally going to receive user input (taken with fgets) as an argument. I have put that aside now, and just decided to give the function a single argument.
This explains why you pass in a char * to your function. The input value was originally going to be read from fgets. In your program, you passed in the name of your variable.
bare example;
/* ... */
print_info("example");
To do a dynamic lookup on a symbol name, use dlsym.
As I suggested in comments, if you want to be able to look up the name of a variable to find the associated object, you can use dlsym so long as you are on a POSIX system (like Linux). For example:
// Need to inlcude <dlfcn.h> and link with -ldl
// Make local variables findable with -rdynamic
void print_info(char *name)
{
bare *p = dlsym(0, name);
if (p != NULL)
printf("The hp of %s is %d", p->name, p->hp);
else
printf("%s not found!\n", name);
}
So long as you include <dlfcn.h> and use -ldl when linking the program, and you make your symbol table visible (with -rdynamic on GCC), the program will find the pointer to your example variable. (Try it online!)
But you probably meant to do a lookup by name.
However, you seemed to have mixed some things up. Usually, the user will not care what names you have used for the variables in your program. You would never expect fgets to give you "example" because that is not what the user would type in.
You probably meant to search for the bare record that matches the name parameter of bare. In your case, "John".
print_info("John");
Normally, you would have a table of bares that you would look over and check for a match. However, in your simplified example, there is only one to check.
bare * find_bare(char *name)
{
if (strcmp(name, example.name) == 0) return &example;
return NULL;
}
void print_info(char *name)
{
bare *p = find_bare(name);
if (p != NULL)
printf("The hp of %s is %d", p->name, p->hp);
else
printf("%s not found!\n", name);
}
It isn't hard to create and search a table of bare.
In this case, you could probably simple create an array of bare to represent your collection that you would search over.
#define BARE_TABLE_SIZE 50
bare table_example[BARE_TABLE_SIZE];
Assuming you add the code to populate your table, you could use a simple loop to search for a matching name.
bare * find_bare(char *name)
{
for (int i = 0; i < BARE_TABLE_SIZE; ++i)
{
if (strcmp(name, table_example[i].name) == 0)
return &table_example[i];
}
return NULL;
}
Your example.name was an uninitialized pointer.
Finally, the most egregious error in your program is the attempt to call strcpy on an uninitialized pointer. One solution is to allocate new memory to hold the new name and assign the location of the new name to the pointer. POSIX systems (like Linux) supply a function called strdup that creates a copy of the input for you, in newly allocated memory.
example.name = strdup("John");
Since the memory is allocated by malloc, you would need to call free on the pointer if example is ever recycled for a new name.
I'm writing a program that writes arrays and the information regarding them to a binary file.
My first approach was to call fwrite 4 times: once for general information regarding the array, once for the timestamp, once for the dimension of the array and once to write the array itself.
This approach worked as it is quite simple, but the execution times were too slow, seeing as the program is multithreaded and it writes to a SAS drive frequently, flooding the drive with requests which presented a bottleneck.
The new approach was to create an array of structs containing the information needed, my struct would be as follows:
struct array_data{
int information;
int timestamp;
int size;
int* data_array;
}
During execution I would write the data to a buffer and when I had everything I need it would call a malloc to allocate array_data.data_array and copy everything from the buffer from inside a for loop.
The issue is when I call fwrite to write the whole struct, the first 3 members of the struct are written correctly, while the array is not and that is due to the address of the array not being contiguous, since it points to another place in memory after the malloc.
The best solution to this would be to declare the data_array as a static array, this way the fwrite would work as I need it to, but then I would have to call fwrite for every struct, instead of calling it once to write an array of structs, which would impact the performance, negating the use of the struct.
I've also tried using an array of dynamically allocated structs, by declaring my struct as follows:
struct array_data{
int information;
int timestamp;
int size;
int data_array[];
}
and allocating the array of structs using malloc, but the address of struct_array[1].information is not the one right after the struct_array[0].data_array[last_index], there seems to be another 5 bytes in between, so if I were to call fwrite with struct_array the data in the file would still be incorrect.
Is there a way to use structs to solve this issue or should I just stick with writing my arrays to the file as I did in the first place?
The following example creates, writes and reads your data. It is just a outline. Error checks on malloc, fread and fwrite ommitted:
#define N_DATA 10
#define N_INTS 5
struct array_data{
int information;
int timestamp;
int size;
int* data_array;
};
struct array_data arr[N_DATA];
void makeData(void){
int i;
for (i=0;i<N_DATA;i++) {
arr[i].data_array=malloc(N_INTS*sizeof(int));
arr[i].size= N_INTS;
}
}
void writeData(FILE *fp_out)
{
int i;
for (i=0;i<N_DATA;i++) {
fwrite(&arr[i],sizeof(arr[i]),1,fp_out);
fwrite(arr[i].data_array,arr[i].size*sizeof(int),1,fp_out);
}
}
void readData(FILE *fp_in)
{
int i= 0;
while(fread(&arr[i],sizeof(arr[i]),1,fp_in)==1) {
arr[i].data_array=malloc(arr[i].size*sizeof(int));
fread(arr[i].data_array,arr[i].size*sizeof(int),1,fp_in);
i++;
}
}
I want to order an array of structs by the first letter of a studentĀ“s name. The code that I made so far is the following:
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int cod;
char* name;
int mark;
}student;
void print(student* class){
int i;
for (i=0;i<4;i++){
printf("%d\n",class[i].cod);
printf("%s\n",class[i].name);
printf("%d\n",class[i].mark);
printf("\n");
}
}
int main(int argc, char *argv[])
{
int ind,i;
int cod=1000;
student class[4];
student temp;
int lengthData=10;
for (i=0;i<4;i++)
{
class[i].name=malloc(sizeof(char)*lengthData);
}
class[0].cod=cod;
class[0].name="Joseph";
class[0].mark=15;
cod++;
class[1].cod=cod;
class[1].name="Jonathan";
class[1].mark=16;
cod++;
class[2].cod=cod;
class[2].name="Karen";
class[2].mark=17;
cod++;
class[3].cod=cod;
class[3].name="Anna";
class[3].mark=20;
print(class);
for (ind=1;ind<4;ind++){
temp=class[ind];
i=ind-1;
while (i>=0){
if (temp.name[0]<class[i].name[0]){
class[i+1]=class[i];
class[i]=temp;
i--;
}
else break;
}
}
printf("ordered data\n");
print(class);
system("PAUSE");
return 0;
}
I am using DevC++ and when I run it the program hangs, but when I add the following lines before the loop for the bubble sort (only for testing):
class[3]=class[2];
printf("%s\n",class[3].name);
for (ind=1;ind<4;ind++){
...
The program works even though one record (3) has been replaced by the data of record (2).
Any help?
You have quite a few problems:
First of all you leak memory, since you allocate memory and make name point to that, then you make name point somewhere else. You need to copyinto the memory you allocate.
Secondly, also with the name member, once you copy into the memory, you will go out of bounds since you only allocate five bytes for each string, but you have strings of up to at least nine characters (ten with the terminator).
Thirdly, and more about going out of bounds, your class array only have three elements, yet you access four elements of the array.
The reassignment of the name pointer won't cause more problems than a temporary memory leak, since you don't attempt to pass the pointer to free. The second problem isn't really an issue because you don't copy the strings yet. The third problem on the other hand, that will lead to undefined behavior as soon as you execute that code.
I want to create a database sort of, that stores a list of 5000 names and 5000 coresponding salaries into an array, I simply can't find the problem since the console either crashes or the compiler gives me the following error: "cannot convert 'char* ()[30]' to 'char' for argument '1' to 'char*' fgets(char*,int,*FILE)".
EDIT: I changed whatever I could figure out in the code, and I seem to have an issue with
this line in particular:
person* TAB = calloc(N, sizeof(struct));
I can't spot other errors(lack of experience), and I don't know exactly what to use instead of fgets to put in a line.
#include <stdio.h>
#include <stdlib.h>
#define N 5000
typedef struct {
char name[30]
int salary;
} person;
int main()
{
person* TAB = calloc(N, sizeof(struct));
FILE * input;
input = fopen("in.txt","r+");
int nr=0;
int r;
while(nr<5000)
{
fscanf(input,"%s",TAB[nr].name);
fscanf(input,"%d",TAB[nr].salary);
nr++;
}
printf("%s %d",TAB[1].name,TAB[1].salary);
fclose(input);
return 0;
}
You really should avoid putting that much data on the stack, which is what a normal variable like that will generally do. It will occupy around 5000 * (30 + 4 * 5000) = 95 MB of stack space, which might be more than your operating system feels is reasonable.
Anyway, the fix is not to allocate this on the heap; the fix is to change the declaration. I believe there's a logic error, since you allocate space for 5000 salaries per person, which is probably not what you meant.
Also, the name field should be an array of characters, but you've declared it as an array of character pointers, which is what the warnings are all about.
I believe you should have:
struct person
{
char name[30];
int salary;
};
This will drop the memory usage for struct person TAB[N]; down to around 5000 * (30 + 4) or around 166 KB which is way more reasonable. This assumes a 4-byte int which is a pretty common situation.
Finally, your file reading code is not very nicely designed, it will probably not work.
Look into using fgets() to read lines, stopping when it fails (i.e. never calling feof()), and then parsing/tokenizing each line as read. Remember that names can contain whitespace, which will make %s in sscanf() stop.
The name struct member should not be declared as 30 char pointers and the salary is one per name so it should look something like this
typedef struct {
char name[30]
int salary;
} person;
Now in order to have it as an array you are best off allocating on the heap
person* persons = calloc(N, sizeof(struct));
Now you can access the name and salary of one person
persons[3].name
persons[3].salary
...
fgets(persons[nr].name,30,input); // although you may want to remove \n
struct person
{
char* name[30];
I think you mean char name[30]. That is if you want one name of at most 29 bytes.
Later on you do:
fgets(&TAB[nr].name,30,input);
Why are you taking the address? If you make the change above, the TAB[nr].name should be of type char[30], which should degenerate into a char* as desired.
I want to use libjudy to build some data structures to store information keyed on fixed length byte arrays, which means that I need to use the JudyHS structures. Based on my understanding of the code and the documentation, a key will only be able to access an element consisting of a single machine word, which would be fine since I want to save a pointer to a struct allocated on the heap; however, there is a problem in that there appears to be no way to iterate over the previously stored elements, and the macro used to deallocate the structure (JHSFA), calls free() on the memory used to store the word of data, but provides no mechanism to allow the calling code to deallocate memory that the word points to. I verified that JHSFA doesn't deallocate user supplied memory using valgrind and the following example code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <judy.h>
int
main(
const int argc,
const char *argv[]
)
{
Pvoid_t table = (PWord_t)NULL;
const size_t allocSize = sizeof("bar") + 1;
char *bar = calloc(1, allocSize);
strncpy(bar, "bar", allocSize);
uint64_t key = UINT32_MAX + 1;
PWord_t entry;
JHSI(entry, table, &key, sizeof(key));
*entry = (Word_t)bar;
entry = NULL;
JHSG(entry, table, &key, sizeof(key));
if (!strncmp(bar, (const char *)(*entry), allocSize)) {
printf("match\n");
}
else {
printf("no match\n");
}
Word_t result;
JHSFA(result, table);
}
Given that this is the case, can some other libjudy user out there point me to a way to avoid a memory leak if this data structure is the only place where I store the data?
JudyHS can't be iterated over. Therefor the typical solution of looping over the entries and freeing the values isn't directly possible. Your options are:
1) Use JudySL and restrict your keys to not having a NULL byte in them. If you need NULL bytes, then you might also consider converting the keys to an escaped format (i.e. one where the NULL byte is a multi-byte escape sequence.)
2) Combine the JudyHS with another ADT that you can iterate over. This ranges in complexity depending on your use case. If you add and remove things from the JudyHS, then its doubtful this can be done in a way that is more efficient than 1). If you only add entires, then a simple linked list, array of pointers, or JudyL will work.