struct pointer member and memory management - c

I'm wondering what happens to a struct member that is pointing to a non-dynamically allocated variable. So:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int value;
int *pointer;
} MyStruct;
int year = 1989;
int main (int argc, const char * argv[]) {
MyStruct *myStruct = (MyStruct *) malloc(sizeof(MyStruct));
myStruct->value = 100;
myStruct->pointer = &year;
year++;
printf("%d \n", *myStruct->pointer);
// what happens to the myStruct->pointer member when we free myStruct ?
free(myStruct);
return EXIT_SUCCESS;
}
I assume it's destroyed an no longer points to year correct? If that is the case, the same would be true if *pointer where pointing to a function right?
like this:
typedef struct {
int value;
void (*someFunc)();
} MyStruct;
Then later:
void sayHi(){
printf("hi");
}
...
myStruct->someFunc = sayHi;
No special cleanup needed except free() if our struct was created with malloc? Thanks for any insights anyone has.

If you didn't malloc (or calloc/strdup/realloc) it you don't need to free it. Nothing special is needed - the member variable just points at something, it doesn't logically "own" the pointed at memory.
Your year member variable will still exist and is perfectly valid after you free(myStruct) - myStruct->pointer will be invalid to use though

Related

What am I doing wrong in passing a struct around in C?

So I am working on a project in C that requires that I pass pointers to a struct into functions. The project is structured as follows:
struct structName {
unsigned short thing2;
char thing1[];
};
void function_1(struct structName *s) {
strcpy(s->thing1, "Hello");
printf("Function 1\n%s\n\n", s->thing1); // prints correctly
}
void function_2(struct structName *s) {
// can read thing2's value correctly
// thing1 comes out as a series of arbitrary characters
// I'm guessing it's an address being cast to a string or something?
printf("Function 2\n%s\n\n", s->thing1); // prints arbitrary characters ('É·/¨')
}
int main() {
struct structName s;
function_1(&s);
printf("Main\n%s\n\n", s.thing1);
function_2(&s);
printf("Main 2\n%s\n\n", s.thing1);
}
This code outputs the following:
Function 1
Hello
Main
Hello
Function 2
É·/¨
Main 2
É·/¨
Obviously, the program has more than just what I've written here; this is just a simplified version; so if there's anything I should check that might be causing this let me know. In all honesty I reckon it's probably just a stupid rookie error I'm making somewhere.
[EDIT: Seems like s.thing1 is being mutated in some way in the call to function_2(), since the odd value is replicated in main() - I should point out that in my program the printf()s are located right before the function call and in the first line of the function, so there's no chance that it's being written to by anything I'm doing. I've updated the example code above to show this.]
Thanks in advance!
The structure contains a flexible member at its end, if you declare a static object with this type, the length of this member will be zero, so strcpy(s->thing1, "Hello"); will have undefined behavior.
You are supposed to allocate instances of this type of structure with enough extra space to handle whatever data you wish to store into the flexible array.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct pstring {
size_t length;
char data[];
} pstring;
pstring *allocate_pstring(const char *s) {
size_t length = strlen(s);
pstring *p = malloc(sizeof(*p) + length + 1);
if (p != NULL) {
p->length = length;
strcpy(p->data, s);
}
return p;
}
void free_pstring(pstring *p) {
free(p);
}
int main() {
pstring *p = allocate_pstring("Hello");
printf("Main\n%.*s\n\n", (int)p->length, p->data);
free_pstring(p);
return 0;
}

How to initialize a struct into a pointed struct

Namaste! I want to initialize my struct array position 0 myList.items[0] with a pointer to my item struct, but it prints out jibberish on the relevant positions when I print it out from my print function. It changes what was previously initialized (for test) so I know it works partially, but what's causing the bad output and what should be changed?
Before:
----My Shopping list---------
1 - Chocolate 40 100g
2 - Fishsauce 9 l
After:
----My Shopping list---------
1 - c┴®¶²` 128565603 ■   lüIv
2 - Fishsauce 9 l
typedef struct{
char name[20];
int amount;
char amountType[10];
}item;
typedef struct{
item *items[5];
int length;
}list;
int addItemToList(list *myList);
main(void)
{
list myList;
myList.length = 0;
for(int i; i<5;i++)
{
myList.items[i] = NULL;
}
addItemToList(&myList);
return 0;
}
int addItemToList(list *myList)
{
item newItem = {"Potatoes",2, "kg"};
myList->items[myList->length]=&newItem; //Something wrong here?
myList->length++;
printf ("Added [%s %i %s] as #%i.", newItem.name, newItem.amount,newItem.amountType, myList->length);
return 0;
}
This:
int addItemToList(list *myList)
{
item newItem = {"Potatoes",2, "kg"};
That allocates newItem on the stack. That means the memory for it will go away when addItemToList is completed, so &newItem will be pointing to gibberish later. It will be fine while still running code in addItemToList, but then after that the memory contents will be replaced in any further functions that are called.
You can either use malloc to allocate some memory for newItem, or you can allocate newItem on the stack in your main function and pass the pointer to newItem to any other called functions.
You cannot initialize a struct on the stack and then pass the pointer to that struct to a different struct that lives longer than that stack frame is open. Once the function returns, the stack frame where your item was allocated will close and the assigned values to the fields will be gone.
You need an initializer function with a heap allocated struct like this:
item* item_new(const char* name, int amount, const char* amountType);
Then your initialization function should:
call Malloc for the size of struct,
Copy the name and amountType strings to the struct.
copy the amount to the struct.
Then you can do this: myList->items[myList->length]=newItem;, where newItem is created by your init function.
You are mixing stack and heap memory, I rewriten it for you, it should give you some sense what went wrong. Also always free allocated memory its no java:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char name[20];
int amount;
char amountType[10];
}item;
typedef struct{
item *items[5];
int length;
}list;
int addItemToList(list *myList);
int main(void)
{
list myList;
myList.length = 0;
for(int i; i<5;i++)
{
myList.items[i] = 0;
}
addItemToList(&myList);
for(int i; i<myList.length; i++)
{
free(myList.items[i]);
}
return 0;
}
int addItemToList(list *myList)
{
item* newItem = malloc(sizeof(item));
strcpy(newItem->name, "Potatoes");
newItem->amount = 2;
strcpy(newItem->amountType, "kg");
myList->items[myList->length++] = newItem; //Something wrong here?
printf ("Added [%s %i %s] as #%i.\n", newItem->name, newItem->amount, newItem->amountType, myList->length);
return 0;
}

"Segmentation fault" when accesing dynamically allocated struct members [duplicate]

This question already has an answer here:
Pointer losing its value + execv compilation warning
(1 answer)
Closed 7 years ago.
I have started to work on a program which implements a structure called "PhoneBook" having two members: "length" and "allocatedSpace", both of type "unsigned int". The structure is dynamically allocated. The two members of the structure are assigned in an external function called "InitializePhoneBook". Now, when I try to print the values of the two members of the structure inside the "main" function I get a "Segmentation fault" error.
PhoneBook.h
#ifndef PHONEBOOK_H
#define PHONEBOOK_H
struct PhoneBook
{
unsigned int length;
unsigned int allocatedSpace;
};
void InitializePhoneBook(struct PhoneBook *phoneBook);
void ClearPhoneBook(struct PhoneBook *phoneBook);
#endif
PhoneBook.c
#include <stdlib.h>
#include "PhoneBook.h"
void InitializePhoneBook(struct PhoneBook *phoneBook)
{
phoneBook = malloc(sizeof(struct PhoneBook) * 1);
phoneBook->length = 0;
phoneBook->allocatedSpace = 1000;
}
void ClearPhoneBook(struct PhoneBook *phoneBook)
{
free(phoneBook);
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "PhoneBook.h"
int main(void)
{
struct PhoneBook *phoneBook;
InitializePhoneBook(phoneBook);
printf("%d %d\n", phoneBook->length, phoneBook->allocatedSpace);
ClearPhoneBook(phoneBook);
return 0;
}
Running "./a.out" with "gdb" I get:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400621 in main () at ./main.c:12
12 printf("%u %u\n", phoneBook->length, phoneBook->allocatedSpace);
When you do malloc in InitializePhoneBook():
phoneBook = malloc(sizeof(struct PhoneBook) * 1);
It doesn't modify the pointer in main because the pointer you assign is local the function. Pass a pointer to pointer or rewrite the function return the malloced pointer.
void InitializePhoneBook(struct PhoneBook **phoneBook)
{
*phoneBook = malloc(sizeof(struct PhoneBook) * 1);
(*phoneBook)->length = 0;
(*phoneBook)->allocatedSpace = 1000;
}
call in main():
InitializePhoneBook(&phoneBook);
and change the prototype:
void InitializePhoneBook(struct PhoneBook **phoneBook);
Other issues I noticed:
You should also check the result of malloc for failure.
Use %u format specifier to print unsigned ints.
C is pass by value. Which means that the parameters are copied when calling a function. Your function InitializePhoneBook() will copy the non-initialised pointer, will assign to that copy the return value of malloc() and then forget that value when leaving the function. Your caller will continue with the un-initialized original.
Your function InitializePhoneBook() can be changed in 2 ways:
struct PhoneBook *InitializePhoneBook(void)
{
struct phoneBook *pb = malloc(sizeof(struct PhoneBook) * 1);
pb->length = 0;
pb->allocatedSpace = 1000;
return pb;
}
or
void InitializePhoneBook(struct PhoneBook **pPhoneBook)
{
*pPhoneBook = malloc(sizeof(struct PhoneBook) * 1);
(*pPhoneBook)->length = 0;
(*pPhoneBook)->allocatedSpace = 1000;
}
the call in main would have to be changed
struct PhoneBook *phoneBook = InitializePhoneBook();
or
struct PhoneBook *phoneBook;
InitializePhoneBook(&phoneBook);
respectively.
The scope of the malloced pointer remains inside the InitializePhoneBook function.
For that you must return the pointer to the main so change the prototype to:
struct PhoneBook *InitializePhoneBook(struct PhoneBook *);
and the last statement of the above function should be:
return phoneBook;
and inside main call it this way:
phoneBook=InitializePhoneBook(phoneBook);

How to memcpy a struct from another similar typedef'ed structure

struct DISPLAY_INFO *display_info;
typedef struct DISPLAY_INFO;
DISPLAY_INFO display_info_2;
Have to copy diplay_info_2 to display_info. How can I do it using memcpy .
Iff (if and only if) display_info points to a valid memory area, you can write
memcpy(display_info, &display_info_2, sizeof(DISPLAY_INFO));
e.g.
#include <stdio.h>
typedef struct DISPLAY_INFO{
int val;
} DISPLAY_INFO;
int main() {
DISPLAY_INFO *display_info;
display_info = (DISPLAY_INFO*)malloc(sizeof(DISPLAY_INFO));
DISPLAY_INFO display_info_2; // The object to be copied
display_info_2.val = 42;
memcpy(display_info, &display_info_2, sizeof(DISPLAY_INFO));
printf("%d", display_info->val);
free(display_info);
return 0;
}
http://ideone.com/AUwDNw
You can do: *display_info = display_info_2.

dynamically expanding array of struct

I am (trying to) write a server-side daemon in c, and it accepts connections from clients. I need a struct that keeps information on each open connection, so I have created an array of my defined struct, and I have it dynamically re-sizing with realloc.
The problem I have is creating the struct within the array. I keep getting this error:
test.c:41: error: conversion to non-scalar type requested
What am I doing wrong?
I spend most of my time in PHP, and am a noob with c. I realize that I am making some simple, beginner mistakes (in other words, feel free to make fun of me). If I am doing something stupid, please let me know. I've put my quality time in with google, but have not figured it out. I have reproduced the issue on smaller scale, as below:
here is my test.h:
typedef struct test_ test;
and here is my test.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "test.h"
//define the struct
struct test_ {
int id;
char *ip;
int user;
char *str;
};
//yes, the list needs to be global
test *test_list;
//
// add an item to the global list
//
int add(int id, char *ip, int size)
{
//
// increment size
if(id>size) {
size = id;
//try to expand the list
test *tmp = realloc(test_list,size);
if(tmp) {
//it worked; copy list back
test_list = tmp;
} else {
//out of memory
printf("could now expand list\n");
exit(1);
}
}
//
// HERE IS THE TROUBLE CODE::
test_list[id] = (struct test)malloc(sizeof(test)+(sizeof(int)*5)+strlen(ip)+1);
test_list[id].id = id;
test_list[id].ip = malloc(strlen(ip));
strcpy(test_list[id].ip,ip);
test_list[id].user = 0;
test_list[id].str = NULL;
}
//
// main
//
int main(void)
{
//initialize
int size = 1;
test_list = malloc(size*sizeof(test));
//add 10 dummy items
int i;
for(i=0; i<10; i++) {
size = add(i, "sample-ip-addr", size);
}
//that's it!
return 0;
}
Try changing
test *tmp = realloc(test_list,size);
to
test *tmp = realloc(test_list,size*sizeof(test));
then delete
test_list[id] = (struct test)malloc(sizeof(test)+(sizeof(int)*5)+strlen(ip)+1);
When you allocate for test_list, there's already space for each member of the struct allocated, so you don't need to do it again. You just have to allocate for any pointers within the struct
The return value from 'malloc' is the memory address you've allocated. You can't cast it to a struct. What would that even mean?
You want something like: test_list=realloc(test_list, num_alloc * sizeof(test_));

Resources