I know I need to use free() in here somewhere, but I'm unsure where.
struct info{
char string1[30];
float float1;
int int1;
char string2[30];
};
struct info* build(){
FILE *data;
int i, lines;
lines=0;
data=fopen("hw3.data","r");
struct info info;
struct info *infoArr;
infoArr = (struct info*)calloc(lines,sizeof(struct info));
for(i=0; i<2; i++){ //change not to 2
fscanf(data, "%s %f %d %s", info.string1, &info.float1, &info.int1, info.string2);
strcpy(infoArr[i].string1, info.string1);
infoArr[i].float1 = info.float1;
infoArr[i].int1 = info.int1;
strcpy(infoArr[i].string2, info.string2);
}
fclose(data);
return infoArr;
}
void function1(){
int i; for(i=0; i<2; i++){
printf("%s %f %d %s\n", build()[i].string1, build()[i].float1, build()[i].int1, build()[i].string2);
}
}
I want to use it at the end of function1(), after the print statement, but will the context still be available there? I don't belief I can free(*infoArr) at the end of build() as I need to access that array elsewhere, which is the whole point of build(). build() is intended to be used in multiple functions. If I use free() at the end of function1(), do I use free(infoArr) or free(build()) or something else entirely?
Also, each of your arguments to printf() is working with a different structure, because you're calling build() repeatedly. You should call build() once before the loop, assign this to a variable, and then loop through the variable.
struct info* temp = build();
for (i = 0; i < 2; i++) {
printf("%s %f %d %s\n", temp[i].string1, temp[i].float1, temp[i].int1, temp[i].string2);
}
free(temp);
You have to save the pointer returned by build(), and free it after the loop. It would be better style though to allocate the memory in function 1 before the loop, have build take a pointer and fill in it's data through that.
Related
when trying to print the values of struct variables after the function returns it prints some random text (which I think is due to memory allocation error)
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char s1[20];
char s2[20];
int n1;
} TEST;
void allocate(TEST *T, int n){
T = malloc(sizeof(TEST)*n);
for(int i=0; i<n; i++){
sprintf((T+i)->s1, "string 1 of %d", i);
sprintf((T+i)->s2, "string 2 of %d", i);
(T+i)->n1 = i;
}
}
int main(){
TEST *T;
int n = 3;
allocate(T, n);
for(int i=0; i<n; i++){
printf("%s\n%s\n%d\n\n", (T+i)->s1, (T+i)->s2, (T+i)->n1);
}
}
No, C absolutely does not call free automatically for you.
The issue in your program is that T in the caller to allocate is not changed. C is strictly a pass by value language.
One solution is to change the type of T to TEST** in allocate:
void allocate(TEST **T, int n){
with
allocate(&T, n);
in main. You then call free in main.
The program causes undefined behaviour by passing uninitialized T to the function. Furthermore you never return the new pointer value from the function back to main.
The pointer to new memory is an output of the function, not an input. So it should be a return value, not a parameter. For example:
TEST* allocate(int n)
{
TEST* T = malloc(sizeof(TEST)*n);
// etc.
return T;
}
and then in main:
TEST* T = allocate(n);
// ... use T ...
free(T);
As said by the already given answers you need to call free to free the memory.
You want to allocate the pointed memory area, so you need a TEST**:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char s1[20];
char s2[20];
int n1;
} TEST;
void allocate(TEST **T, int n){
*T = malloc(sizeof(TEST)*n);
for(int i=0; i<n; i++){
sprintf((*T+i)->s1, "string 1 of %d", i);
sprintf((*T+i)->s2, "string 2 of %d", i);
(*T+i)->n1 = i;
}
}
int main(){
TEST *T;
int n = 3;
allocate(&T, n);
for(int i=0; i<n; i++){
printf("%s\n%s\n%d\n\n", (T+i)->s1, (T+i)->s2, (T+i)->n1);
}
free(T);
}
No. The problem with your program is that T is passed by copy to allocate, and the address to the allocated memory is assigned to this copy. To fix, you could make the first allocate parameter **T, pass in the address of T in main, and dereference the pointer to pointer in allocate and assign to it.
No, it doesn't. You need to free() malloc()ated memory yourself.
Your program, as is, leaks memory... but for this particular program it doesn't matter an awful lot since that memory is freed when the process dies.
I'm working on a function that works as part of a larger program. My C pointer skills are a bit rusty and so I need some help here.
I keep getting segmentation fault errors, and I feel like there is a very trivial solution to my question, and any explanation would help!
Essentially, I have an empty array of structs that I need to pass through to a function as a double pointer. That function will open and read a file saving the contents of the file in the array of structs.
I need to pass it as a double pointer.
This is what I have so far:
struct node{
int first_value;
int second_value;
};
unsigned char readFunction(char *fileName, int *limit, struct node **arrayToFill){ //Many more variables passed, but I removed it for the sake of simplicity
FILE *input;
input = fopen(fileName, "r");
if (input == NULL) {
printf("error: could not read the input file!\n");
}
int i=0;
int temp1, temp2;
for(i=0; i<(*limit); i++){
fscanf(input, "(%d, %d)", &temp1, &temp2);
(*(arrayToFill+i))->first_value = temp1;
(*(arrayToFill+i))->second_value= temp2;
}
//More code
return 0; //Actually returns another array but that's irrelevant.
}
int main(){
//NOTE: I just created these variables for the sake of showing it on StackOverflow, I still get a Segmentation Fault error when I run the program.
char name[9] = {'t', 'e', 's', 't', '.', 't','x','t', '\0'};
struct node arrayToPass[10];
struct node *pointer = &arrayToPass;
struct node **data = &pointer;
unsigned char returnedVal;
int limit = 10;
returnedVal = readFunction(&name, &limit, data);
return 0;
}
Thanks in advance!
You have several problems. The first is you are using the arrayToPass[10] pointer incorrectly, all you need is:
int main (void) {
struct node arrayToPass[10];
int limit = 10;
printf ("return: %hhu\ncontent:\n", readFunction(NULL, &limit, &arrayToPass));
for (int i = 0; i < limit; i++)
printf ("%5d %5d\n",
arrayToPass[i].first_value, arrayToPass[i].second_value);
}
Do not attempt to cast around your struct node (*arrayToPass)[10] pointer when you pass the address by assigning to different pointers. You begin with type struct node [10] (array of struct node [10]) when you take the address you have struct node (*)[10] (pointer to array of struct node [10]). It is separate and district from struct node ** (pointer to pointer to struct node).
Your function then takes the type struct node (*arrayToFill)[10], e.g.
unsigned char readFunction (char *fileName, int *limit, struct node (*arrayToFill)[10])
{ //Many more variables passed, but I removed it for the sake of simplicity
FILE *input;
input = fileName ? fopen (fileName, "r") : stdin;
if (input == NULL) {
printf("error: could not read the input file!\n");
}
int i=0;
int temp1, temp2;
while (i < *limit && fscanf(input, " (%d, %d)", &temp1, &temp2) == 2) {
(*arrayToFill)[i].first_value = temp1;
(*arrayToFill)[i].second_value = temp2;
i++;
}
*limit = i;
return 0; //Actually returns another array but that's irrelevant.
}
(note: the use of the ternary operator allowing NULL to be passed as fileName to read from stdin -- that was just for my convenience)
(also note: that since you declare struct node arrayToPass[10]; with automatic storage duration in main(), you don't need to pass the address of the pointer, you only need to pass the address of the pointer if the address can changes in your function -- such as if you call realloc on the pointer. The other answer addresses that point.)
The difference between needing to pass struct node ** or struct node (*)[10] or simply struct node * boils down to how memory is allocated for the original collection. If as you have done, declaring struct node arrayToPass[10]; in main() with automatic storage duration, storage for the array is fixed. On access, the array is converted to a pointer (struct node *) and you can simply pass the array itself as the parameter. (but you are limited to no more than the number of elements originally declared)
If however, you have an allocated storage type for arrayToPass in main (e.g. struct node *arrayToPass = malloc (10 * sizeof *arrayToPass);, then if you need to change the amount of storage, e.g. the number of stuct node that your allocated block of memory can hold in readFunction(), then you must pass the address of the pointer, so if reallocation takes place, and the beginning address for your block of memory changes, that change will be seen back in the caller (main() here). In that case when you pass the address of struct node *, then your type becomes struct node **. (because you have taken the address of a pointer instead of the address of an array)
Since your arrayToPass can't be reallocated, and the storage is fixed before it is passed to readFunction(), you don't need to pass the address and you can eliminate one level of pointer indirection and just pass the array as type struct node *. That simplifies access in your function to simply arrayToFill[i].first_value = temp1;, the [..] acting as a dereference of the pointer, just as -> does.
You also may want to change the return type from unsigned char to size_t and return the number of elements filled in your struct (a meaningful return) -- or you can update the limit pointer as I did -- your choice.
The complete example is:
#include <stdio.h>
struct node {
int first_value;
int second_value;
};
unsigned char readFunction (char *fileName, int *limit, struct node (*arrayToFill)[10])
{ //Many more variables passed, but I removed it for the sake of simplicity
FILE *input;
input = fileName ? fopen (fileName, "r") : stdin;
if (input == NULL) {
printf("error: could not read the input file!\n");
}
int i=0;
int temp1, temp2;
while (i < *limit && fscanf(input, " (%d, %d)", &temp1, &temp2) == 2) {
(*arrayToFill)[i].first_value = temp1;
(*arrayToFill)[i].second_value = temp2;
i++;
}
*limit = i;
return 0; //Actually returns another array but that's irrelevant.
}
int main (void) {
struct node arrayToPass[10];
int limit = 10;
printf ("return: %hhu\ncontent:\n", readFunction(NULL, &limit, &arrayToPass));
for (int i = 0; i < limit; i++)
printf ("%5d %5d\n",
arrayToPass[i].first_value, arrayToPass[i].second_value);
}
Example Input File
$ cat dat/2x8rand.txt
(17987, 1576)
(12911, 4488)
(30688, 5875)
(25617, 16643)
(8999, 26249)
(29270, 31857)
(8954, 2094)
(21390, 27676)
Note the change in the fscanf format-string including an additional ' ' (space) before the opening parenthesis '(' to consume the '\n' (and any leading whitespace). You cannot use any input function correctly unless you check the return (e.g. fscanf(input, " (%d, %d)", &temp1, &temp2) == 2)
Example Use/Output
$ ./bin/ptrtoarraystruct < dat/2x8rand.txt
return: 0
content:
17987 1576
12911 4488
30688 5875
25617 16643
8999 26249
29270 31857
8954 2094
21390 27676
Look things over and let me know if you have further questions.
I believe you may want something like the following.
#include <stdio.h>
struct node{
int first_value;
int second_value;
};
unsigned char readFunction(char *fileName, int limit, struct node *arrayToFill){ //Many more variables passed, but I removed it for the sake of simplicity
FILE *input;
input = fopen(fileName, "r");
if (input == NULL) {
printf("error: could not read the input file!\n");
}
int i=0;
int temp1, temp2;
for(i=0; i<limit; i++){
fscanf(input, "(%d, %d)", &temp1, &temp2);
arrayToFill[i].first_value = temp1;
arrayToFill[i].second_value = temp2;
}
//More code
return 0; //Actually returns another array but that's irrelevant.
}
int main(){
//NOTE: I just created these variables for the sake of showing it on StackOverflow, I still get a Segmentation Fault error when I run the program.
char name[9] = "test.txt";
struct node arrayToPass[10];
unsigned char returnedVal;
int limit = 10;
returnedVal = readFunction(name, limit, arrayToPass);
return 0;
}
I'm learning pointers and struct now and I'm a bit confused. Particularly, I want to make a function which returns a pointer to a struct. My code is compiling, but it isn't working. After I type the number of students, it asks for name and age (without reading name), and after I type the age, it closes.
#include <stdio.h>
#include <stdlib.h>
struct details
{
char name[100];
int age;
};
struct details * details_pointer(int n)
{
struct details pointer_x[n];
struct details *pointer = pointer_x;
for (int i=0; i<n; i++)
{
printf("Student %d:\n", i);
printf("name:\n");
fgets(pointer[i].name, 100, stdin);
printf("age:\n");
scanf("%d", pointer[i]. age);
}
return pointer;
}
int main()
{
int n;
printf("Type the number of persons:\n");
scanf("%d", &n);
struct details *student = details_pointer(n);
printf("\nName: %s\n", (*student).name);
printf("Age: %d\n", (*student).age);
system("pause");
return 0;
}
The problem here is that you're returning a structure variable (pointer_x) that's allocated locally on the stack of the inner details_pointer() function, but this memory is no longer reserved for you once it returns. This means you get (at best) garbage.
You have to either allocate memory in the function and return it (and remember to free it!) or pass the data to the function to fill it in.
void get_details(int n, struct details p[n])
{
for (int i = 0; i < n; i++)
{
// do stuff with p[i]
}
}
int main()
{
...
scanf("%d", &n);
struct details students[n];
get_details(n, students);
printf("\nName: %s\n", students[0].name);
...
}
I generally prefer passing data to the function when possible just because it simplifies memory management.
EDIT: Two notes about your existing details_pointer() function.
1) In fgets(pointer[i].name, 100, stdin), it's a good practice to derive the number of bytes from the size of the array if it's known; in this case it is, so recommend fgets(pointer[i].name, sizeof(pointer[i].name), stdin). Yours is not incorrect, but it's easier to maintain should the sizes change in the future.
2) the scanf("%d", pointer[i].age) needs to take the address of the .age to stuff its value in there; you're passing a number instead of an address, which is for sure incorrect.
Ok, so if the assignment requires dynamic allocation, then that's what we have to do.
Just specifying an array implicitly allocates the space while the function is running, but it disappears when the function returns. You'll need to allocate it specifically.
Revisiting your code:
struct details *details_pointer(int n)
{
struct details *students = (struct details *)malloc(n * sizeof(struct details));
.... do stuff with students[0] and the like
return students;
}
This uses the malloc() - memory allocate - library function to get you some space, and it remains valid until you release it. The number of bytes is how many things you want (n) times how many bytes in one thing (sizeof(struct details))
Later:
int main()
{
struct details *student = details_pointer(n);
.. do stuff
free(student);
}
This now uses that memory, and releases it back to the OS when you're done.
I am creating a program that modifies a dynamic array. It must initialize the array and be able to insert into it. I have been unable print the array after in order to test it, how would I go about this?
Piece of relevant code:
typedef struct {
char first;
char second;
} name;
typedef struct {
int number;
name name;
} data;
/*points to array, number allocated, number used*/
typedef struct {
data *info;
size_t numof;
size_t numused;
} list;
void init(list *l) {
l->data = malloc(sizeof(l) * l->numof);
l->numused = 0;
l->numof = 2;
}
int insert(list *l, const data *dat) {
if (l->numused == l->numof) {
l->numof *= 2;
l->data = (int *)realloc(l->data, l->numof * sizeof(int));
}
l->data[l->numused++] = *dat;
return 0;
}
int main(void) {
int i;
list l;
data list1;
/*example info for testing*/
list.number = 1234;
strcpy(list1.name.first, "abc");
strcpy(list1.name.second, "xyz");
init(&l);
insert(&l, list1);
/*runs through array elements to print*/
for (i=0; i < ((int)sizeof(&l)) /(int)sizeof(&l); i++) {
printf("%s\n", list1);
}
return 0;
}
Edit: I just need to know how to print the array to see if I'm doing it correctly, the code above will have errors as I had been messing around trying to figure it out.
strcpy(list1.name.first, "abc");
strcpy(list1.name.second, "xyz");
These both will invoke undefined behaviour as first and second are declared as char variables , and you copy string literals to them .
You need to declare both of them as character arrays .
And this -
for (i=0; i < ((int)sizeof(&l)) /(int)sizeof(&l); i++) {
printf("%s\n", list1);
}
You try to print struct variable list1 with %s specifier, maybe you tend to print the strings that you wanted to copy. So directly print list1.name.first and list1.name.second in printf with %s specifier.
And the condition -
i < ((int)sizeof(&l)) /(int)sizeof(&l)
The cast is not necessary , and it will yield 1 so, loop will run for 1 time . Change the condition .
In your code, the member of structure name is defined as char. But you are trying to copy a string into it. May be this was a typo. If not you should define them as character array or character pointer. Also in your print statement you are trying to print structure data as string. It should be like -
printf("%s %s\n", list1.name.first, list1.name.second);
Also you assigned value 1234 to list.number. You may have meant list1.number. The parameters in function call of insert is wrong as well. And lastly, you have put l->data in functions init and insert which should be l->info.
Hi I'm trying to read variables from a file into a int array so I can store them in a Struct array. The numbers get stored correctly into the curLinks array but when I try pass the curLinks array into curNodes.nodes, it doesn't work and when i try print it out (to test) it prints rubbish numbers. Any help would be great.
struct nodeInfo* getTopology(FILE *file){
int totLinks=0;
fscanf(file, "%d", &nodeCount);
struct nodeInfo netTopo[nodeCount];
// How many links does node have
for (int id=0; id<nodeCount; id++){
struct nodeInfo curNode;
curNode.n=id;
fscanf(file, "%d", &totLinks);
int curLinks[totLinks];
for(int i=0; i<totLinks; i++){
int digit=0;
fscanf(file, "%d", &digit);
curLinks[i] = digit;
}
curNode.nodes = curLinks;
netTopo[id] = curNode;
}
for (int id=0; id<nodeCount; id++){
for (int j=0; j<3; j++){
printf("%d ", netTopo[id].nodes[j]);
}
}
return netTopo;
}
You define curLinks multiple time in the first for-loop
int curLinks[totLinks];
And after you fill that you try to set that in your nodeinfo however as soon as the next iteration in the for-loop is entered and curLinks is filled again, the memory of your previous curLinks is out of scope and the memory where you think your read in values should reside can be actually filled with anything - Undefined Behaviour
If you tell me the way you define your structs nodeInfo I might be able to show you how to do it properly.
e.g.: Assuming you define
struct nodeinfo {
int *nodes;
};
Then
struct nodeInfo* getTopology(FILE *file)
{
int id, digit=0, totLinks=0;
fscanf(file, "%d", &nodeCount);
struct nodeInfo netTopo[nodeCount];
// How many links does node have
for (id=0; id<nodeCount; id++){
fscanf(file, "%d", &totLinks);
netTopo[id].nodes = malloc(totLinks * sizeof(int));
if (netTopo[id].nodes==NULL)
printf("Error allocating memory\n");
for(i=0; i<totLinks; i++) {
fscanf(file, "%d", &digit);
netTopo[id].nodes[i] = digit;
}
}
// Free the allocate memory
for (id=0; id<nodeCount; id++){
free(netTopo[id].nodes);
}
return netTopo;
}
I think you should use pointers and "malloc" to allocate memory from the heap in this case.