How to create an array of struct pointers to NULL - c

I want to create an array of struct pointers and set each pointer to null. Eventually I want to have the pointers in the array point to my struct. I believed I had the write code to this but I keep getting a seg fault.
Code:
//struct in my .h
struct bin{
double cac; // current available capacity
struct node *list //pointer to linked list... bin struct points to linked list struct
}
//main file
void main(){
struct bin *bArray[20];
struct bin *binTemp, *pTemp;
for(i=0;i<20;i++) bArray[i]= NULL;
}
I assumed this would create an array of bin pointers, but I'm getting a seg fault here. Shouldn't I be able to make all the pointers NULL regardless of what type of pointer they are?
Eventually I want to make these all point to bin structs and I thought I could do this without having to make the pointers NULL first so i tried:
for(i=0;i<20;i++){
binTemp = (struct bin *)malloc(sizeof(struct bin));
binTemp->cac = 1.0;
binTemp->list = NULL;
bArray[i] = binTemp;
}
Once again I got a seg fault. I have no idea whats going on here. I know seg faults means I'm trying to write to an illegal memory location which makes me think I would have to set the size of the array indexes with malloc. However,
for(i=0;i<20;i++) bArray[i]= malloc(sizeof(struct bin));
also gives me a seg fault. I have no idea what I'm doing wrong.
Actual code I ran:
//Header File
#ifndef hBin_h
#define hBin_h
#include <stdio.h> // stdio used for file io
#include <stdlib.h> // standard c library
#define MAX_S 20
//bin struc
struct bin {
double cac; //current available capacity
struct node *list; // pointer to linked list
};
//linked list node struct
struct node{
char *name; //name of item
double size; // weight of item
struct node *next; //pointer to next
};
//insert the new item into a node in its appropriate location using alphabetical ordering of item names
struct node *oInsert(char *item, double size, struct node *head);
//print the items of the list out along with the list’s capacity
void traverse(struct node *head);
// deallocate the nodes of the list
void destory(struct node *head);
//input info from file - name of object, weight of object
void input(FILE *inFile, char item[], double *weight);
#endif // hBin_h
#include "hBin.h"
void main(){
FILE *inFile;
char *item;
double *weight;
struct bin *bArray[20];
int i;
struct bin *binTemp, *pTemp;
inFile = fopen("run1.txt", "r"); //open file
printf("HERE1\n");
for(i=0;i<20;i++){
binTemp = (struct bin *)malloc(sizeof(struct bin));
binTemp->cac = 1.0;
binTemp->list = NULL;
bArray[i] = binTemp;
}
/*while(!feof(inFile)){
input(inFile, item, weight);
printf("%s, %.2f\n", item, *weight);
}*/
}
I used gdb (not totally sure what I'm doing here):
(gdb) run
Starting program: /home/Christopher/CSC362/Pass_F/Main
[New Thread 813244.0xc7590]
[New Thread 813244.0xc6ce0]
[New Thread 813244.0xc7320]
[New Thread 813244.0xc5994]
HERE1
0 [main] Main 813244 cygwin_exception::open_stackdumpfile: Dumping stack trace to Main.exe.stackdump
[Thread 813244.0xc7320 exited with code 35584]
[Thread 813244.0xc6ce0 exited with code 35584]
[Inferior 1 (process 813244) exited with code 0105400]
(gdb) where
No stack.
(gdb) for(i=0;i<20;i++){
binTemp->cac = 1.0;
binTemp->list = NULL;
bArray[i] = binTemp;
} /usr/src/debug/cygwin-2.2.1-1/winsup/cygwin/crt0.c: No such file or directory.
(gdb) binTemp = (struct bin *)malloc(sizeof(struct bin));
Undefined command: "binTemp". Try "help".
(gdb) binTemp->cac = 1.0;
Undefined command: "binTemp->cac". Try "help".
(gdb) binTemp->list = NULL;
Undefined command: "binTemp->list". Try "help".
(gdb) bArray[i] = binTemp;
Undefined command: "bArray". Try "help".
(gdb) } for(i=0;i<20;i++){
Undefined command: "". Try "help".
(gdb) binTemp = (struct bin *)malloc(sizeof(struct bin));
Undefined command: "binTemp". Try "help".
(gdb) binTemp->cac = 1.0;
Undefined command: "binTemp->cac". Try "help".
(gdb) binTemp->list = NULL;
Undefined command: "binTemp->list". Try "help".
(gdb) bArray[i] = binTemp;
Undefined command: "bArray". Try "help".
(gdb) } for(i=0;i<20;i++){
binTemp->cac = 1.0;
Undefined command: "". Try "help".
(gdb) binTemp = (struct bin *)malloc(sizeof(struct bin));
Undefined command: "binTemp". Try "help".
(gdb) binTemp->cac = 1.0;
Undefined command: "binTemp->cac". Try "help".
(gdb) binTemp->list = NULL;
Undefined command: "binTemp->list". Try "help".
(gdb) bArray[i] = binTemp;
Undefined command: "bArray". Try "help".

Reading your code you commented out, you pass the variable weight to the input function and right after dereference it in your call to printf. There is a major problem here, and that is that the variable weight is not initialized, and that passing it to a function passes it by value, which means that the variable is copied and the function only operates on the copy and not the original, meaning that the weight variable in your main function will still be uninitialized when you dereference it and that leads to undefined behavior and a probable crash.
If you intend to emulate pass by reference (you can only emulate since C doesn't have passing by reference), you should declare weight as a normal variable, and use the address-of operator when calling the function:
double weight;
...
input(inFile, item, &weight);
// ^
// |
// Note ampersand here
You have a similar problem with the item variable. It's uninitialized and doesn't point anywhere special. Using it in any way except to initialize it will lead to undefined behavior. And if you try to initialize it in the input function then you have the same problem as described above, and you need to pass a pointer to the pointer using the address-of operator.
If you don't initialize the item pointer in the input function, but use it like it's already pointing to some valid memory (using e.g. strcpy or similar function) then you also have undefined behavior.
The actual crash you experience might be totally unrelated to the problems I describe above, since you seem to be doing something involving linked lists, which of course means pointers, and pointers used wrongly will give you many chances for further undefined behaviors and crashes.
The first thing you should do is enable more warning when building, as the compiler is usually very good at finding suspect behavior that can lead to UB. You do that by adding e.g. the flags -Wall -Wextra -pedantic when building.

Related

Struct | assign struct objects | Segmentation Fault Error

I define a struct type as follows:
typedef struct {
int obs_flag;
double obs_timestamp;
int event_mask;
char *event_name;
char *filedir;
} structdata;
where I have a pointer named obs_data:
structdata *obs_data;
then I want to assign each object of the obs_data as follows:
int observer_flag = 1;
double ctime = 2309212380.323100;
struct inotify_event* event = (struct inotify_event*)(buffer + bytesProcessed);
obs_data->obs_flag = observer_flag;
obs_data->obs_timestamp = ctime;
obs_data->event_mask = event->mask;
obs_data->event_name = event->name;
obs_data->filedir = "./myDir/";
in the above, event is a struct from the inotify that captures the events associated with changes to a file or directory in Linux.
when I run the above chunk of code in my program I encounter the Segmentation fault (core dumped).
I am not a pro working with stucts and pointers. Any help is greatly appreciated.
Your obs_data is just a pointer!! It's not an instance of structdata. If you want it to be a pointer, you need to malloc memory to hold the struct.
So before using obs_data you need code like:
obs_data = malloc(sizeof *obs_data); // Allocate memory for 1 instance of structdata
if (obs_data == NULL)
{
// allocation failed
exit(1);
}
// Now you can assign values like
obs_data->obs_flag = observer_flag;
...
...
and once you are done using it, remember to free the memory like
free(obs_data);

C pointer address changes on null pointer initialization in function

Disclaimer: I am new to C arrived here from other languages. What I observe breaks my head I do not even have a starting point to explain the observed behavior.
Scenario: Play around with a self-written stack implementation to get a feeling for the language and to compare different approaches.
Compiler in use:
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
Minimized code example:
#include <stdio.h>
struct stack_entry
{
struct stack_entry *next;
int *item;
};
struct stack
{
struct stack_entry *first;
};
void push_to_stack(struct stack *s_ptr, int *item)
{
struct stack_entry new_entry = {.next = s_ptr->first, .item = item};
s_ptr->first = &new_entry;
printf("item_address#push_to_stack %p\n", s_ptr->first->item);
}
void pop_from_stack(struct stack *s_ptr)
{
printf("item_address#pop_from_stack %p\n", s_ptr->first->item);
int* result = NULL;
}
int main()
{
printf("\n--stack test--\n");
struct stack s = {};
struct stack *s_ptr = &s;
int value = 42;
push_to_stack(s_ptr, &value);
printf("item_address#main: %p\n", s_ptr->first->item);
pop_from_stack(s_ptr);
return 0;
}
Unexpected output:
--stack test--
item_address#push_to_stack 0x7fffa759b67c
item_address#main: 0x7fffa759b67c
item_address#pop_from_stack 0x7fffa759b680
As one observes the item_address#pop_from_stack differs for some reason. I expect the output:
--stack test--
item_address#push_to_stack 0x7ffdc30ee19c
item_address#main: 0x7ffdc30ee19c
item_address#pop_from_stack 0x7ffdc30ee19c
To receive the expected output I need to remove the pointer declaration+initialization. In case I leave it in place the unexpected output occurs. So the following does the change:
// int* result = NULL;
But why? This totally puzzles me.
This will trigger undefined behavior later on:
struct stack_entry new_entry = {.next = s_ptr->first, .item = item};
s_ptr->first = &new_entry;
because new_entry will die when push_to_stack() ends.
But why? This totally puzzles me.
When compiled without optimizations, that line is likely making the compiler allocate space for result in the pop_from_stack() frame. Such a thing will make the behavior of the program change due to the undefined behavior shown above.

Segmentation Fault in hsearch

I am using (http://linux.die.net/man/3/hsearch) in my source code. I wrote a very basic code to test the hash functionality (did not want to reinvent the wheel by writing my own hash implementation). I see that it crashes with a segmentation fault in the search routine.
Any idea why its crashing?
#include <stdio.h>
#include <search.h>
#include <stdlib.h>
char *data[] = {
"cpe1","cpe2","cpe3","cpe4","cpe5","cpe6","cpe7","cpe8","cpe9","cpe10","cpe11","cpe12","cpe13"};
int main()
{
ENTRY ep, ep1, *ep_ptr, ep2;
int loop;
char *ptr;
char input[100];
hcreate (30);
for (loop=0; loop<13;loop++)
{
ptr = malloc (100);
sprintf (ptr, "%d.%d.%d.%d%c", loop+1, loop*2, loop*3, loop, '\0');
ep.key = data[loop];
ep.data = (void *) ptr;
printf ("%s --> %s\n", ep.key, (char *) ep.data);
ep_ptr = hsearch(ep, ENTER);
}
ep2.data = (void *) "cpe1";
ep_ptr = hsearch(ep2, FIND);
printf("%9.9s -> %9.9s: %s\n", ep2.key,
ep_ptr ? ep_ptr->key : "NULL", ep_ptr ? (char *)(ep_ptr->data) : "NULL");
return 0;
}
OUtput:
(gdb) r
Starting program: /home/globus/code/cpe/a.out
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000
cpe1 --> 1.0.0.0
cpe2 --> 2.2.3.1
cpe3 --> 3.4.6.2
cpe4 --> 4.6.9.3
cpe5 --> 5.8.12.4
cpe6 --> 6.10.15.5
cpe7 --> 7.12.18.6
cpe8 --> 8.14.21.7
cpe9 --> 9.16.24.8
cpe10 --> 10.18.27.9
cpe11 --> 11.20.30.10
cpe12 --> 12.22.33.11
cpe13 --> 13.24.36.12
Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:32
32 ../sysdeps/x86_64/multiarch/../strlen.S: No such file or directory.
(gdb) bt
#0 __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:32
#1 0x00007ffff7b0ba71 in __GI_hsearch_r (item=..., action=FIND, retval=0x7fffffffdfd8,
htab=0x7ffff7dd67d0) at hsearch_r.c:149
#2 0x00007ffff7b0b92e in hsearch (item=..., action=<optimized out>)
at hsearch.c:34
#3 0x00000000004007a0 in main () at hash_test.c:32
(gdb)
While searching you should set ep2.key to search for the entry not ep2.data. So update your code to
//--v
ep2.key = (void *) "cpe1";
ep_ptr = hsearch(ep2, FIND);
As you have not set ep2.key the hsearch() function tries to access uninitialized pointer causing segmentation fault.
ep2.data = (void *) "cpe1";
ep_ptr = hsearch(ep2, FIND);
That first statement there is in error, you need to set the key to what you want to find, not the data.
Because you haven't set the key to anything, it has some arbitrary value in it (it's not static storage duration, so it's not initialised).
Then, hsearch is then running string functions on it (such as strlen) which is why you're getting the crash:
Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ...
^^^^^^^^^^^^^
(running string function on non-string).
Your code should instead be:
ep2.key = (void *) "cpe1";
ep_ptr = hsearch(ep2, FIND);
In last printf, ep2.key which is not initialized
i notice a few things.
You are allocating ptr repeatedly within the loop but you are not freeing it. So thats a memory leak right there.
What is the data type for ep.data? Why do you have to convert to (void *)? Then again you are converting it to (char *)!!. Why?? If you data is already of char type then why this need to convert to (void *) repeatedly?
Fix these errors and then give it a try.
That line does not look correct:
ep2.data = (void *) "cpe1";
I found the definition of ENTRY so you'll have a better view of why it does not work as expected:
typedef struct entry {
char *key;
void *data;
} ENTRY;
You need to first allocate both key and data before copying all the bytes in it.

Queues - "dereferecing pointer to incomplete type"

So, I'm trying to write a few tests. I have a file called listQueue.c (not shown but working) which contains a series of a bunch of function operations on 'queues'. Now my problem lies when I try to write some tests for one of the functions in listQueue.c in a separate file I called testQueue.c.
My listQueue.c:
// Creates an empty Queue
Queue createQueue (void){
Queue q = malloc (sizeof (*q));
assert(q != NULL);
q->head = NULL;
q->tail = NULL;
q->size = 0;
return q;
}
testQueue.c contains:
int main (int argc, char *argv[]){
printf("Test 1 - Testing create q\n");
Queue q = createQueue();
printf("%d", q->size);
assert(q->head == NULL);
assert(q->tail == NULL);
printf("All tests passed, createQueue works fine.\n");
return 0;
}
The 'header file' Queue.h "
typedef struct queueImp *Queue;
//Function Prototypes
Queue createQueue(void);
Now when I tried to compile it it spits out an error.
"Dereference pointer to an incomplete type." I suspect it's something to do with how I called createQueue. Any help would be appreciated. Thanks. And yes I have included Queue.h above my main!
When you deference q in main(), compiler hasn't seen the definition of struct queueImp yet. Hence, it errors out as the compiler can't determine the size of the object.
Put the defintion of struct queueImp (not sure where you have it at the moment -- I don't see anywhere in your posted code) in queue.h and make sure to include it.

Segfault from adding a variable

I'm admittedly a straight-C newbie, but this has got me stumped. I'm working on a linked list implementation for practice, and I'm getting a segfault by simply adding a variable to the split_node function:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Node {
struct Node *child;
char *content;
};
void print_list(struct Node node);
void split_node(struct Node *node, int position);
int main() {
struct Node head, second, third;
head.content = "first";
second.content = "second";
third.content = "i'm third";
head.child = &second;
second.child = &third;
print_list(head);
split_node(&head, 3);
print_list(head);
return 0;
}
void print_list(struct Node node) {
printf("%s\n", node.content);
if(node.child) print_list(*node.child);
}
/*
Split node into two nodes, with the first position characters of the node's content remaining with node, and the remainder being copied to the new node. (It doesn't yet truncate the first node's string, but does do the copy.)
*/
void split_node(struct Node *node, int position) {
if(position >= strlen((*node).content)) return;
struct Node newNode;
newNode.child = (*node).child;
(*node).child = &newNode;
int length = (strlen((*node).content) - position);
newNode.content = malloc(sizeof(char) * (length + 1));
strncpy(newNode.content, (*node).content + sizeof(char) * position, length);
newNode.content[length] = '\0';
//int foo;
}
This code compiles (gcc -Wall -o list list.c) and runs fine:
$ ./list
first
second
i'm third
first
st
second
i'm third
But if I uncomment int foo at the end of split_node, compile and run, I get:
$ ./list
first
second
i'm third
first
st
Segmentation fault
gdb gives me this backtrace:
#0 0x91d6ae70 in strlen ()
#1 0x91dd3126 in puts ()
#2 0x00001f21 in print_list (node={child = 0xbcec815b, content = 0x8b000000 <Address 0x8b000000 out of bounds>}) at list.c:41
#3 0x00001f3c in print_list (node={child = 0x8fe0154b, content = 0x1ff6 "i'm third"}) at list.c:42
#4 0x00001f3c in print_list (node={child = 0xbffff568, content = 0x1fef "second"}) at list.c:42
#5 0x00001f3c in print_list (node={child = 0xbffff570, content = 0x1fe9 "first"}) at list.c:42
#6 0x00001ee0 in main () at list.c:33
Why would adding a variable definition cause a segfault? It appears to be smashing the content pointer of the newly created node. I'm confused; any help?
You need to dynamically allocate your nodes (using malloc).
As you have it, your new node is declared on the stack. When the split function returns, that new node is no longer valid memory.
Adding a variable causes a segfault because that variable changes the layout of the stack causing slightly different behavior when the function returns.
Try setting the Nodes child property to NULL, C doesn't automagically zero out memory so it looks like your may have garbage in child (or your could use calloc instead of malloc). SoapBox's answer is also correct.
Valgrind is a great tool to help find these types of problems. You can just do "valgrind myappname" from the command line and it will give you details on these types of errors.

Resources