I got a problem with checking whether a member of a struct is null or not. For example:
typedef struct {
int value;
} A;
int main() {
A *foo = malloc(sizeof(A));
foo->value++; // obviously, null pointer error
}
Then I attempted to check whether value is NULL or not by:
if (foo->value != NULL) {
foo->value++;
}
But the error occured: comparison between pointer and integer.
What should I do? Note that set it to 0 is not an option in my circumstance.
You probably meant
if (foo)
foo->value++;
Also your comment "obviously null pointer error" is not so obvious to me.
foo->value++; // obviously, null pointer error
Not so obvious to me why this is an error. value is an int, not an int *, so how can it ever be a NULL pointer?
I think you meant to perform the following check
A *foo = malloc(sizeof(A));
if( foo != NULL ) {
foo->value++; // increment value
} else {
// allocation failed, do something about it
}
When you malloc a structure enough memory is allocated to contain all members of that structure; you do not have allocate memory for every single member.
Note that the contents of the structure itself are uninitialized after the malloc call. To set the members to a deterministic state you can do any one of the following:
foo->value = 0; Similarly initialize all other members
memset( foo, 0, sizeof(*foo) ); This sets all bits within the structure to zeros
A *foo = calloc( 1, sizeof(A) ); calloc automatically zero initializes the allocated memory
An int isn't a pointer. It can't be NULL (or at least that value is indistinguishable from zero).
That's an int, not a pointer, so it doesn't make much sense to compare it to NULL. If you want to be able to do that, then you need to declare it in the struct as an int*. Otherwise just make sure you initialize it to 0 when you create the struct.
To expand on the above, it's important to be aware that when you malloc() that struct, the space for that int is ALREADY IN the space provided by the malloc(). The struct literally contains the int, not just a pointer to it.
The int type is not a pointer so it can not be a NULL pointer. When you create a struct enough room is allocated for your values but you still need to initialize its contents, otherwise they will be set to what was previously in the allocated space, and sometimes this best done using another function.
A *createA()
{
A *a = malloc(sizeof(A));
//TODO: make sure a is no null
a->value = 0;
return a;
}
Calling createA will now always return a struct with the int value set to 0.
As others have pointed out, int is not a pointer type and cannot be NULL. However, I believe what you were trying to get at by the 'obviously, null pointer error' remark was that memory obtained from malloc is not initialized, so foo->value++ won't necessarily leave you with 1. To fix this you can either use calloc or memset:
calloc:
int main() {
A *foo = calloc(1, sizeof(A)); // returns 0'd memory
foo->value++;
}
memset:
int main() {
A *foo = malloc(sizeof(A));
memset(foo, 0, sizeof(*foo)); // sets the contents of the struct to 0
foo->value++;
}
You can also manually 0 the fields, which works fine, but you leave yourself open to forgetting to zero new fields you add to the struct later.
Related
I have the following struct definition (names have been generalised):
typedef struct structure{
int *array1;
int *array2;
} structure_t;
I need to initialise this struct data structure through a function which takes in the sizes of the two arrays as parameters. The function returns a pointer to that data structure and NULL on fail.
I am getting confused on how to go about this. I know that I cannot return a pointer of a locally declared struct, and I also know that I need to dynamically allocate memory for the two members array1 and array2, since the size is not known on compile time (it's inputted by this user). I have tried the following:
structure_t* init(int size1, int size2)
{
structure_t *st = malloc(sizeof (structure_t));
if(st == NULL) return NULL;
st->array1 = malloc((sizeof (int))*size1);
st->array2 = malloc((sizeof (int))*size2);
return st;
}
I have checked and everything is being initialised. But then when I come to free the memory it is not working properly, as only the pointer to array1 is being changed to NULL.
bool destroy(strcuture_t *st)
{
free(st->array1);
free(st->array2);
free(st);
if (st == NULL)
return true;
else
return false;
}
What am I doing wrong?
free does not change the value of the pointer passed to it. It cannot, as it receives only the value and not a reference to the pointer.
To record that a pointer no longer points to valid memory, you can set the pointer to NULL yourself after calling free, as with:
free(st);
st = NULL;
Further, once the memory pointed to by st is freed, the C standard does not define the behavior of accessing st->array1 or st->array2 or even of using the value of st at all. There is no reason to expect that checking st->array1 or st->array2 for a null pointer will produce any particular result. The comparison may evaluate to true, may evaluate to false, may cause your program to abort, or may cause your program to misbehave in other ways.
I have to set a reference pointed by a pointer to NULL.
But the function deleteP(...) doesn't seem to work, indicated by the Output.
The functions delete() and memoryset() work in some way, even if the latter just fills the memory (pointed to by the pointer in the array) with zeroes.
I want the pointer in the array to finally be NULL and that is not working.
I need to do everything (i.e. set fs->child[20] to NULL etc.) via pointer to the struct (which is elin my code, a local pointer variable inside deleteP(...) ). This is because I am iterating over fs children, and their children after that, a lot of times, and I put the current child in el.
How could I solve it?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define HEIGHT 255
#define LENGTH 256
#define MAX_CHILDREN 1024
typedef struct FS FS;
typedef struct Elem Elem;
struct Elem {
char name[LENGTH];
char content[256];
int isFile;
int emptyCells;
Elem *child[MAX_CHILDREN];
};
struct FS {
int emptyCells;
Elem *child[MAX_CHILDREN];
};
void delete(FS *fs){
free(fs->child[20]);
fs->child[20] = NULL;
}
void deleteP(FS *fs){
Elem *el = calloc(1, sizeof (Elem));
el = fs->child[20];
free(el);
el = NULL;
}
void memoryset(FS *fs){
Elem *el = calloc(1, sizeof (Elem));
el = fs->child[20];
memset(el, 0, sizeof(Elem));
}
int main(int argc, const char * argv[]) {
FS *fs = calloc (1, sizeof(FS));
fs->emptyCells = MAX_CHILDREN;
fs->child[20] = calloc (1, sizeof(Elem));
strcpy(fs->child[20]->name, "Hello");
printf("No delete: %s\n", fs->child[20]->name);
memoryset(fs);
printf("MEMSET: %s\n", fs->child[20]->name);
fs->child[20] = calloc (1, sizeof(Elem));
strcpy(fs->child[20]->name, "Hello");
delete(fs);
printf("Delete: %s\n", fs->child[20]->name);
fs->child[20] = calloc (1, sizeof(Elem));
strcpy(fs->child[20]->name, "Hello");
deleteP(fs);
printf("DeleteP: %s\n", fs->child[20]->name);
}
Output:
No delete: Hello
MEMSET:
Delete: (null)
DeleteP: Hello
Allow me to phrase your goal in my words
(after verifying my understanding in chat):
you want to free memory pointed to by a pointer which is stored in an array,
which is inside a struct, which you get a pointer to
you cannot access the array member directly,
only via the pointer to the containing struct
you also want to write NULL to the array member
looking at your code, you attempted to do that by making a copy of the array member (which is a pointer)
it mostly works, only that the array member does not end up being NULL
(and some problems mentioned by xing and BLUEPIXY)
Basically, you need a pointer to the array member, instead of a copy of the array member.
So your function should be:
void deleteP(FS *fs){
Elem **el; // pointer to pointer, instead of pointer (and no calloc)
el = &(fs->child[20]); // pointer to array member
free(*el); // free the pointer in the array member (not a copy of it),
// though the effect is the same
*el = NULL; // write NULL to the array member, not a copy of it,
// this is what changes the effect to what you want
}
If I did not mistype anything, this is more or less the result of our chat.
And as far as I understand, it solves your problem. Cheers.
As far as I can tell, this should also fix the memory leak found by xing inside deleteP(...).
But be careful to also fix it in memoryset(...).
This does NOT fix the problems of UB (undefined behaviour) as found by BLUEPIXY.
For this you need to rework your debug prints and make sure not to dereference any pointers to already freed memory (question of order of doing things) and also not to dereference any pointer which was set to NULL.
By the way, this could be done without a local pointer variable; doing everything via the parameter fs. But I kept the solution closer to your own code for better clarity of what is the difference. Also in my opinion your way of doing it via local pointer is more readable. It might even be faster, but seeing how good modern compilers are, I doubt it; the actual reason is clarity and readability.
I have N statically allocated structures.
struct exemple{
...
}
struct exemple array[N];
struct exemple *test_ptr = 0x3; /* random address */
Can I check if test_prt points to a valid address? i.e. it points to one "struct example" allocated.
You can't. You have to know. It's not a problem if you manage your pointers correctly. A good habit is to always set pointers to 0 / NULL as soon as you destroy the object they point to. Then you can just test with if (ptr) or if (!ptr) (or, more verbose: if (ptr == NULL) / if (ptr != NULL)).
Note that your last assignment
struct exemple *test_ptr = 0x3; /* random address */
is invalid. you can't assign an integer to a pointer. but you can cast it to the pointer type;
struct exemple *test_ptr = (struct exemple *)0x3; /* random address */
The result will depend on your implementation / system.
You can only check if pointer is valid by doing pointer != NULL because anything except `NULL' is treated by valid pointer.
In your case, to check if your pointer points to any of your array entry, you can only do this:
size_t i = 0;
int isValid = 0;
for (i = 0; i < N; i++) {
if (test_ptr == &array[i]) {
isValid = 1;
break;
}
}
if (isValid) {
//Pointer points to one of your array entry
}
But in general, you cannot just test if pointer points to specific valid location for you. It is up to you to take care of where it points. It can also have NON-NULL value but points to invalid location, for example:
int* ptr = malloc(10); //Now points to allocated memory
*ptr = 10;
free(ptr); //Free memory
*ptr = 10; //Undefined behaviour, it still points to the same address but
//we don't know what will happen. Depends on implementation
In general, no, you can't test if a pointer is valid or not.
But, if you want to know if a pointer points to an element of an array, you can:
if(test_ptr >= &array[0] && test_ptr < &array[N]
&& ((intptr_t)test_ptr - (intptr_t)array)%((intptr_t)(&array[1]) - (intptr_t)array) == 0) {
// test_ptr points to an element of array
}
This works because arrays are allocated contiguously.
There is no language method but in some circumstances you can try to have some known values at the certain points of the structure. If the pointed memory location has those values you can assume it as valid - but of course you do not have any guarantee. But you need to write your own functions when you create the structure, and when you destroy it (by filling with zeros before freeing the memory). It is a very week workaround - but if you connect with another measures and accept the overhead it makes the probability of the incorrect program behaviour lower.
Sometimes it is called a security cookie.
it is possible of course to make it more complicated - at certain positions you have only offsets to those cookies. It makes less probable that the random position in the memory will have such a chain of data :)
I don't know if I get your question properly.
If you want to know if a pointer points to a struct of some type (cast my structs to void * and vice-versa, for example), I do the next way:
#include <assert.h>
struct my_struct {
#ifndef NDEBUG
#define MY_STRUCT_MAGIC 0x1234abcd
uint64_t magic;
#endif
int my_data;
};
void init_struct(struct my_struct *s, int t_data) {
#ifdef MY_STRUCT_MAGIC
s->magic = MY_STRUCT_MAGIC;
#endif
s->my_data = t_data;
}
my_struct *my_struct_cast(void *vs) {
my_struct *s = vs;
#ifdef MY_STRUCT_MAGIC
assert(MY_STRUCT_MAGIC == s->magic);
#endif
return s;
}
It has a little bit more code because of inclusion of const-casting, but I think you get the idea.
If you want to know if test_ptr points to a aray member, you have to check this way: test_ptr >= array && test_ptr < &array[sizeof(array)/sizeof(array[0])]). If the pointer comes from void, char, or some kind of dangerout ariyhmetic, you could also check for test_ptr % sizeof(array[0])
If you want to know if a pointer points to valid memory "ever allocated" by your program, you will have to intercept allocs functions, save returned chunks pointer & size, and compute like the previous example.
I have a pointer to several structures that have been allocated memory via:
STRUCTNAME *ptr;
ptr = (STRUCTNAME *)malloc(sizeof(STRUCTNAME)*numberOfStructs);
The structures are accessed via a offset like so:
(ptr + i)->field;
The structures have 2 fields that are character pointers as follows:
typedef struct
{
char *first;
char *second;
}STUCTNAME;
These fields are allocated memory as follows:
(ptr + i)->first = (char *)malloc(strlen(buffer));
This appears to work but when I try to free the pointers within the structures I get a segmentation fault 11 when I do this:
free((prt + i)->first);
Help?
Notes:
buffer is a character array. Offsetting a pointer by a integer should increment the pointer by the size of what it is pointing to times the integer correct?
Here is a link to my full source code. I have not written some of the functions and I am not using the freeAllpointers and printAll yet.
https://drive.google.com/file/d/0B6UPDg-HHAHfdjhUSU95aEVBb0U/edit?usp=sharing
OH! Thanks everyone! Have a happy Thanksgiving! =D (If you're into that kinda stuff)
In case, you don't initialize all those members in that piece of code, you're not showing us:
Allocate the struct storage (STRUCTNAME*) with calloc(), so that all allocated memory, namely firstand second are zero at the beginning. Passing NULL to free() will result in a no-op. Passing any wild (garbage) pointer to free() may cause a segmentation fault.
To detect a double-free, set ptr[i].first = NULL; after free(ptr[i].first); as a defensive measure for testing.
Notes: buffer is a character array. Offsetting a pointer by a integer
should increment the pointer by the size of what it is pointing to
times the integer correct?
Yes, except for void* on those compilers, which don't define sizeof(void), which is defined to have undefined behavior, to a value > 0: What is the size of void?
Edit:
void makeReviews(FILE *input, REVIEW *rPtr, int numReviews) <-- This does NOT return the new value of rPtr. In main(), it will remain NULL.
Do something like this:
REVIEW* makeReviews(FILE *input, int numReviews);
//...
int main(){
//...
rPtr = makeReviews(input,numReviews);
//...
}
or
void makeReviews(FILE** input,REVIEW** rPtrPtr,int numReviews){
REVIEW* rPtr = *rPtrPtr;
//...
*rPtrPtr = rPtr;
}
//...
int main(){
//...
makeReviews(input,&rPtr,numReviews);
//...
}
fgets(cNumReviews, sizeof(cNumReviews), input); <-- Perhaps, you could use something like fscanf().
I have a struct defined as
struct _element;
typedef struct _element Element;
struct _element {
char* StudentName;
char* StudentID;
int StudentMarks;
};
A pointer to an Element struct is declared globally as
Element * ePtr;
Now I have a function that returns a pointer to an Element struct. This is defined as shown below. The same ePtr which was declared globally is populated in this function and then returned.
Element * CreateElement(char * jName, char * jID, int jMarks)
{
printf("CreateElement \n");
puts(jName); puts(jID); printf("%d\n",jMarks);
ePtr->StudentName = (char*)malloc(sizeof(char)*strlen(jName));
strcpy(ePtr->StudentName, jName);
printf("After Creation \n");
puts(ePtr->StudentName);
return ePtr;
}
I am calling this function using
ePtr = CreateElement(iName,iID,iMarks);
from another function. The values stored in the parameters are correct, as shown by puts and printf commands just below the function call line.
My problem is that I'm getting a segmentation fault at the
ePtr->StudentName = (char*)malloc(sizeof(char)*strlen(jName));
line. I checked the same using gdb.
Are you allocating any memory for ePtr?
Just declaring a pointer to this struct globally isn't enough: you'll need to malloc some memory for it also: ePtr = malloc(sizeof(Element);.
Also be sure to add an extra slot in the malloc for your strings for the null terminator.
Generally, always initialize your pointers to NULL - you can do that when you declare the global: Element *ePtr = NULL;. Furthermore, try to get your ePtr out of the global-scope, and, check for NULL before you use a pointer, as with ePtr in your CreateElement method.
You need to assign some memory for ePtr before you can assign memory to the char* that it contains. Do a malloc on your ePtr at the start of the function.
There is also little point in declaring ePtr globally, but this isn't what is breaking the program.
ePtr = (Element*)malloc(sizeof(Element));
You should probably also check if ePtr is null after this before using it (can be null if out of memory as well as some other issues).
You don't assign any memory to
ePtr = (Element*)malloc(sizeof(Element));
before you start assigning values to it and ultimately return it from the function.
Also you need to allow space for the nul terminator of your string
ePtr->StudentName = (char*)malloc(sizeof(char)*(strlen(jName) + 1));
Finally don't forget to allocate memory for and copy the value of the ID, and copy the studentMarks into Element.
Remember, the Element is fixed-size. It needs memory to hold the two char * as well as the one int. It does not matter that the strings are variable length when allocating memory for Element.