Union as a Structure Variable in C - c

I have the following structures:
complex_attribute
generic_attribute
I defined a union of these two, like so:
union union_attribute{
struct complex_attribute *complex;
struct generic_attribute *generic;
};
And then i defined another structure which keeps track of the union and a code associated with it:
struct tagged_attribute{
int code;
union union_attribute *attribute;
};
Then, i defined another structure called Disk, which contains an array of pointers to tagger_attribute objects:
struct disk {
struct tagged_attribute *attribute_ptr[100];
}
Now I am trying to access the code of the tagged attribute like this:
printf("%i", disk_ptr->attribute_ptr[counter]->code);
But I am getting a segmentation fault. Is my way of accessing the structure variable "code" incorrect?
Here is all of the relevant code from where I am trying to access "code":
struct disk* construct_disk(char* name, char* serial, char* vendor, char* model, int RPM, char *raid_type, int num_args, ...){
struct disk *disk_ptr;
disk_ptr = malloc (sizeof (struct disk));
va_list ap;
va_start(ap, num_args);
int counter;
int incrementer;
//subattributes is a global variable
incrementer = subattributes[counter];
for(counter = 0; counter < num_attributes; counter++, incrementer = subattributes[counter]){
printf("Counter = %i\n", counter);
printf("incrementer = %i\n", incrementer);
if (1){
printf("Populating generic attribute");
printf("%i", disk_ptr->attribute_ptr[counter]->code);
//disk_ptr->attribute_ptr[counter]->code = GENERIC_ATTRIBUTE_TYPE;
//disk_ptr->attribute_ptr[counter]->attribute->generic = construct_generic_attribute(va_arg(ap, int));
}else{
printf("Populating complex attribute");
//struct generic_attribute* input_to_complex_attribute[incrementer];
//int stepper;
//for(stepper = 0; stepper<incrementer; stepper++){
// input_to_complex_attribute[stepper] = construct_generic_attribute(va_arg(ap, int));
//}
//disk_ptr->attribute_ptr[counter]->code = COMPLEX_ATTRIBUTE_TYPE;
//disk_ptr->attribute_ptr[counter]->attribute->complex = construct_complex_attribute(5, incrementer, input_to_complex_attribute);
}
}
va_end(ap);
return disk_ptr;
}

You aren't accessing code at all (which you should be using to check which union member is valid, of course).
You're accessing the counterth element of the attribute_ptr array, which is a pointer to a tagged_attribute and trying to dereference it (with ->). Possibly without allocating that pointer (or any of the others in that array) first, nor initialising the memory after allocation (you haven't shown anything about that... failure to allocate correctly is a likely cause of your segfault.)
Of course, this assumes disk_ptr has been allocated and initialised correctly... which you haven't shown and may not have.
As already mentioned, show all relevant code if you want a more specific answer to your question. Further, compile with warnings enabled and learn to use tools such as gdb (GNU debugger) and valgrind (for memory issues) to debug your code.
EDIT: Now that you've added code, you have allocated disk_ptr but you never allocate anything in attribute_ptr, so it's just 100 pointers pointing to arbitrary places in memory.

You are dereferencing disk_ptr->attribute_ptr[1], but that array of pointers is not initialized (the pointers point nowhere).
You have to malloc the struct tagged_attribute entries for each pointer first.

In C if a pointer is not pointing to valid memory you will have undefined behavior. One of the common things that happens is a segmentation fault as the pointer has random chunk or was initialized to zero and when you try to access the memory it is pointing to the hardware detects that you are accessing an invalid memory page. Every time you use -> you are dereferencing the pointer and run the risk of a seg fault. You should use a debugger to find the incorrect value. An alternative is to print the values before you dereference them:
printf("disk_ptr = %p\n", disk_ptr);
printf("disk_ptr->attribute_ptr[counter] = %p\n", disk_ptr->attribute_ptr[counter]);
You should place this code before the print that you shows. If disk_ptr is an invalid value the second print will fail. The first print will always succeed but you should see if it is NULL or not. If you do not see the second print that means the disk_ptr is an invalid pointer. This because in the second print disk_ptr is dereferenced via the -> operator and if it points to chunk it could (let me emphasize could) cause a seg fault (it could also overwrite some other data which might cause a seg fault later). If the second print works but the print you shows does not then disk_ptr->attribute_ptr[counter] could be the invalid pointer. Let me emphasize again because it is important. If a pointer is not pointing to a correct memory location you have undefined behavior. Dereferencing that pointer could cause a seg fault right there or could modify memory in some way such that a seg fault occurs later.

Related

When writing a function that returns pointer, why should I allocate memory to the pointer I'm going to return?

I'm a bit weak when it comes to memory allocation and pointers.
So, I want to understand why do I have to allocate memory to pointers in functions as follow:
char *cstring(char c, int n)
{
int i = 0;
char * res;
res = malloc ((n+1)*sizeof(char));
while (i<n)
{
res[i]=c;
i++;
}
res[i] ='\0';
return res;
}
and why is the following not valid?
char *cstring(char c, int n)
{
int i = 0;
char * res;
while (i<n)
{
res[i]=c;
i++;
}
res[i] ='\0';
return res;
}
I understand that I should allocate memory (generally) to pointers so that they have defined memory.
However, I want to mainly understand how is it related to the concept of stack and heap memories!
Thanks in advance!
Pointers need to point to a valid memory location before they can be dereferenced.
In your first example, res is made to point at a block of allocated memory which can subsequently be written to and read from.
In your second example, res remains uninitialized when you attempt to dereference it. This causes undefined behavior. The most likely outcome in this case is that whatever garbage value it happens to contain will not be a valid memory address, so when you attempt to dereference that invalid address your program will crash.
If you declare a variable like that,
int A = 5;
then that means the variable will be on the stack. When functions are called, their local variables are pushed to the stack. The main function is also an example of that. So you don't have to allocate memory manually, your compiler will do this for you in the background before it calls your main function. And that also means if you examine the stack during the execution of the function you can see the value 5.
With this,
int A = 5;
int *PtrToA = &A;
The pointer will be on the stack again. But this time, the value on the stack just shows the memory address of the actual integer value we want. It points to the address of the memory block that holds the value 5. Since A is held in the stack here, pointer will show a memory address on the stack.
Like the case in your question you can allocate memory dynamically. But you have to initialize it before you read it. Because when you request to allocate the memory, your operating system searches for a valid memory field in your programs heap and reserves that for you. Than it gives you back its adddress and gives you the read write permissions so you can use it. But the values in it won't contain what you want. When compiler allocates on stack, the initial values will be unset again. If you do this,
char *res;
res[1] = 3;
variable res will be on the stack and it will contain some random value. So accessing it is just like that,
(rand())[1] = 3;
You can get an access violation error because you may not have permission to write to that memory location.
An important note; after your function call returns, values of local variables on the stack are no more valid. So be careful with that. Do not dereference them after the function call ends.
In conclusion; if you want to use a pointer, be sure it points to a valid memory location. You can allocate it yourself or make it point another memory address.
The second version of your code declares a pointer, but does not initialize it to point to a valid memory address.
Then, the code dereferences that pointer -- during the loop. So, your code would access uninitialized memory in this case. Remember, array indexing is just syntactic sugar for dereferencing -- so your code accesses memory its not supposed to.
The first version of your code initializes the pointer to actually point to something, and hence when you dereference it during the loop, it works.
Of course, in either case, you return the pointer from the function -- its just that in the first version it points to something valid, whereas in the second version it points anywhere.
The moral here is to always initialize your variables. Not doing so could result in undefined behavior in your code (even if it appears to work sometimes). The general advice here is to always compile your code using at least some compilation flags. For example in gcc/clang, consider -Wall -Werror -Wextra. Such options often pick up on simple cases of not initializing variables.
Also, valgrind is a brilliant tool for memory profiling. It can easily detect uses of uninitialized memory at runtime, and also memory leaks.
Simple: because you do not have any allocated memory for the data you wite. In your example you define pointer, you do not initialize it so it will reference random (or rather not possible to predict) place in the memory, then you try to write to this random memory location.
You have 2 Undefined Behaviours here in 5 lines example. Your pointer is not initialized, and you did not allocate any valid memory this pointer to reference.
EDIT:
VALID
char *cstring(char c, int n)
{
char * res;
res = malloc ((n+1)*sizeof(char));
char *cstring(char c, int n)
{
char * res;
static char buff[somesize];
res = buff;
char buff[somesize];
char *cstring(char c, int n)
{
char * res;
res = buff;
INVALID
char *cstring(char c, int n)
{
char * res;
char buff[somesize];
res = buff;

Accessing members of a passed struct array in C

I have a method levenshtein that populates a 2D array of structs w/ info and returns a pointer to that array. When I send it to another method, I get a Segmentation Fault (core dumped) error at runtime. Please help me w/ this hopefully obvious error.
struct chartEntry
{
int num;
bool left,
up,
diag;
};
struct chartEntry** levenshtein(char *s1, char *s2, bool toPrint)
{
unsigned int s1Len,
s2Len,
i, //rows, general purpose index
j; //columns, general purpose index
s1Len = strlen(s1);
s2Len = strlen(s2);
/***********************************
Create and populate traceback chart
***********************************/
struct chartEntry chart [s1Len+1][s2Len+1];
//
// code to populate chart here
//
//prints expected number
printf("chart[3][3].num is %d", chart[3][3].num);
return chart;
}
void testFunction(char*s1,char*s2)
{
// both of these give segmentation faults
printf("[3][3].num is %d", levenshtein(s1,s2,false)[3][3].num);
struct chartEntry ** tmp = levenshtein(s1,s2,false);
printf("[3][3].num is %d", tmp[3][3].num);
}
There's 2 problems here. Firstly, chart is an array of arrays. This cannot be converted to a pointer-to-a-pointer. Arrays and pointers are different. Your line return chart; must give you a compilation error which you should not ignore.
Secondly, even if it could be converted, chart's memory is local to the levenshtein function and will no longer exist when that function returns. So you would be returning a wild pointer.
You have two options:
allocate memory for chart using malloc and return a pointer to that (either one large block, or with two levels of indirection)
have the caller allocate the array and the levenshtein function just writes values into it.
If you use the first option then you should not use the printf as you have done the first time in testFunction, because the memory would not be freed. You have to save the returned pointer, printf it, and then execute a sequence of free that is the reverse of the malloc sequence you used to allocate it.
In your code, you're trying to return a pointer to an array that's declared inside the function:
struct chartEntry** levenshtein(char *s1, char *s2, bool toPrint)
{
// ...
struct chartEntry chart [s1Len+1][s2Len+1];
// ...
return chart;
}
However, as soon as the program exits this function, this array falls out of scope and is destroyed, leaving you with a pointer pointing to invalid memory. This leads to undefined behavior: Maybe it works, maybe it doesn't, maybe it puts your computer on fire. Okay, that last one is pretty unlikely, but the point is, anything can happen.
There are two ways to deal with this problem:
Create a static array before calling the function, and then pass a pointer to this array in the function call.
Dynamically allocate memory in the function, which can then be returned as a normal pointer. (The calling function has to make sure the memory is freed after use, though, otherwise this may lead to memory leaks, which is a bad, bad thing.)

initialising a structure through pointer

Suppose we have
struct me {
int b;
};
void main() {
struct me *m1;
m1->b=3;
}
My quesrion is that , as m1 is a pointer of type me and is currently
not holding any address of variable of type me then how we can access b which is member of me
through a pointer which is not pointing to any variable of type me and if we can then which variable of type me is accesing a?
It's either
struct me m1;
m1.b = 3;
or
struct me *m1 = malloc(sizeof(struct me));
m1->b = 3;
When you deal with pointers in C, you usually need to do 3 things:
create the pointer
make sure the memory is allocated where the pointer should point
make the pointer point to that memory
Your solution only did the first of these.
The reason why your printf works, is that the actual assignment and reading still works. You were overwriting some random memory in your process, this time without any disastrous result. But it's pure "luck". You could have ended up with a segmentation fault as well.
1) You must allocate space for the object you're pointing to first
2) Then - and only then - can you assign the value m1->b = 3
void main()
{
struct me *m1=malloc(sizeof(struct me)); //here allocating the memory first
m1->b=3;
//do what you want to do
free(m1); //once you allocate the memory, you have to free it after your job is done
}
If you do not allocate memory and access (like you have done), you are accessing a part of memory where m1 points to. It will compile fine. But if m1 has a value outside the segment of your code, it will give rise to segmentation fault. Also if it is within your segment, it may overwrite other values. So it is always desirable to allocate the memory before using it.

Determining whether a struct member has valid data before trying to free() it

I am using the code below to free up malloced memory in the meshes struct, which contains triangleArrays and faces.
This crashes because not every position in the struct has data. What I want to do is only call free if the struct contains data at that member of the array. However using if (self.meshes[meshIdx].triangleArrays[triangleArrayIdx].faces !=NULL) does not seem to work.
for (int meshIdx = 0; meshIdx <=meshTriangleArrays; meshIdx ++) {
for (int triangleArrayIdx = 0; triangleArrayIdx <=1; triangleArrayIdx ++) {
if (self.meshes[meshIdx].triangleArrays[triangleArrayIdx].faces !=NULL) {
free(self.meshes[meshIdx].triangleArrays[triangleArrayIdx].faces);
}
}
}
Calling free on a null pointer is actually fine.
You haven't given enough code to fully diagnose this problem, but a few things to look at:
You need to make sure that self.meshes[...].triangleArrays[...].faces is always initialized, either by a call to malloc (or whatnot), or by setting it to NULL. Otherwise it can (and likely will) be a random garbage pointer that you don't have permission to free.
You need to make sure that all the different self.meshes[...].triangleArrays[...].faces pointers are distinct pointers. You are only allowed to call free exactly once on a malloc'd pointer. For example, something like this:
int * p = (int *) malloc(sizeof(int));
free(p);
free(p); // undefined behavior
can cause a crash.
The below code crashes because not every position in the struct has data.
No, it doesn't crash due to passing a NULL pointer to free(). If you pass in a NULL pointer nothing happens, see the documentation.
What error is being thrown? Show us your initialization code as well, i.e., how are you allocating faces and everything above it? You are likely passing in some bad/uninitialized data to free().
BTW, due to the way you have asked this question I am lead to believe that you think simply declaring an array will fill every element with NULL. This is not the case, they may be filled with anything, and if you pass that to free you will crash (if you're lucky).
How was the triangleArrays array created in the first place? Is it possible that the non-allocated members contain garbage instead of NULL?

Variable Declaration in C

I am trying to declare a integer variable m and a pointer to integer data type n.
int m,*n;
*n=2;
printf("%d",*n);
above code works fine.
But
int *n,m;
*n=2;
printf("%d",*n);
gives segmentation fault.
please explain why?
Both versions are wrong—you just got lucky with the one that worked. You've declared a pointer but not allocated any storage for it. Try this:
int *n,m;
n=&m;
*n=2;
printf("%d",*n);
Or using malloc():
int *n;
n=malloc(sizeof(int));
*n=2;
printf("%d",*n);
free(n);
Both code segments invoke undefined behaviour, because you dereference an uninitialized pointer. When there is UB, nasal demons fly out of your nose... or your program orders pizza, or it crashes, or it works... You must alllocate memory first.
int* n = malloc(sizeof(int));
*n = 2;
free(n);
Or set it to an address of another object;;
int *n, m;
n = &m;
*n = 2;
When you declare a pointer variable, it allocates some block of space in memory. This space already contains some data left over from whatever it was used for before this program. It gives a segmentation fault because whatever data is in the pointer refers to a memory location outside of your space on the hard drive. As Armen said, you have to initialize the pointer by telling it where to point. This will replace the data currently in the pointer with the address of your variable m (or wherever you want it to point).
n is uninitialized pointer. Access to it causes error.
You are lucky the first one works at all. Both of them are accessing a non-initialized pointer.
What does "n" point to? Since it is uninitialized, it is pointing to nothing. In each case, you are assigning whatever n is pointing to the value of 2. The first will eventually lead to a nasty bug. You are lucky on the second one because it crashed right away.
Use malloc to create some memory for n to point to, and then assign it.

Resources