I have this code, which is part of a library for handing a database (as a linked list):
char *db_getVal(char *key, Node *database) {
while(database != NULL){
if(strcmp(key, database->key) == 0){
return database->value;
}else{
database = database->next;
}
}
return NULL;
}
It works fine when I use a key that exists in database, but when I enter a key that does not, I get a segmentation fault. Why is that?
Make sure the last element's next member is set to NULL. If it's not explicitly set, it might be some junk value that's not NULL but nevertheless will cause your program to receive a segmentation fault if accessed.
When you generate the database link, make sure its last item database->next set to null
Related
I am using the jansson library for a C project.
I have some problem understanding how to use the decref. Shall it be used after each new json_t parameter or not? As I understand jansson will borrow references to make this simpler.
If I run this program and check the values of a_id and a_test they are the same. I expected error or null for a_test.
I tried the same idea but then I added decref for json_acc and json_param but it crashed before I could even read the 1:th value. I was assuming a crash but not until a_test.
This is part of a bigger project but I try to add an example to show the essentials.
API side:
json_t* parObj;
void loadFile(char* path)
{
json_error_t error;
parObj = json_load_file(path, 0, &error);
}
int getAccountId(char* id)
{
json_t* json_acc = json_object_get(parObj, "accounts");
json_t* json_param = json_object_get(json_acc, id);
return json_integer_value(json_param);
}
void cleanJson()
{
json_decref(parObj);
}
Caller side:
loadFile("/home/jacob/accountDump.json");
int a_id = getAccountId("10");
cleanJson();
int a_test = getAccountId("10");
I did misunderstood how it is supposed to work, I assumed that decref would also set the memory to zero.
The API will remove the references and make it a free memory but as long as no one writes there or memset it to zero and the pointer is not set to null I can still read the values from that pointer.
I've done some looking around and can't really find a good source that even addresses the idea.
First: It's well known that we should always check if malloc() and realloc() return null. This is commonly done in some way similar to:
Word* temp;
if ((temp = (Word*)malloc(sizeof(Word))) == NULL) {
fprintf(stderr, "unable to malloc for node.\n");
exit(EXIT_FAILURE);
}
However, we also generally build binary search trees in a recursive manner, like so:
void buildTree(Word** tree, const char* input) {
//See if we have found the spot to insert the node.
//Do this by checking for NULL
if (!(*tree)) {
*tree = createNode(input);
return;
}
//else, move left or right accordingly.
if (strcmp(input, (*tree)->data) < 0)
buildTree(&(*tree)->left, input);
else
buildTree(&(*tree)->right, input);
return;
}
So, what do we do if we start working with massive data sets and malloc() fails to allocate memory in the middle of that recursive buildTree function? I've tried a number of things from keeping track of a "global error" flag and a "global head" node pointer and it just seems to be more and more messy the more I try. Examples working with building BSTs rarely seem to give any thought to malloc() failing, so they aren't really helpful in this regard.
I can logically see that one answer is "Don't use recursion and return the head of the tree each time." and while I can see why that would work, I'm an undergraduate TA and one of the things we use BSTs to teach is recursion. So, saying "don't use recursion" to my students when we are TEACHING recursion would be self-defeating.
Any thoughts, suggestions, or links would be greatly appreciated.
We usually use a return error and let the caller free it, after all it could very well free other non critical resources and try to insert the node again.
#define BUILD_OK 0
#define BUILD_FAILED 1
int buildTree(Word** tree, const char* input) {
int res;
//See if we have found the spot to insert the node.
//Do this by checking for NULL
if (!(*tree)) {
if (!(*tree = createNode(input)))
return BUILD_FAILED;
//Maybe other checks
return BUILD_OK;
}
//else, move left or right accordingly.
if (strcmp(input, (*tree)->data) < 0)
res = buildTree(&(*tree)->left, input);
else
res = buildTree(&(*tree)->right, input);
return res;
}
I am trying to print out the contents of a 2 dimensional array starting from a certain location in the array (since not all elements of the array are filled). The array contains pointers to a data structure I created called a node. Here is the print code:
void repository_print(int print_elements){
node *travTemp;
travTemp = main_list[highest_level][0];
while((travTemp->down)!=NULL){
while((travTemp->next)!=NULL){
printf(" {%d, %d}", travTemp->key, travTemp->d);
travTemp = travTemp->next;
}
travTemp = travTemp->down;
printf("\n");
}
}
Basically the array holds pointers to node elements in a sorted fashion. Each node contains a "key" attribute and a "d" attribute and I am just trying to go level by level and print out the {key, d} records cleanly. I keep getting a segfault when I call the print command in my main. I tried using gdb to debug it but it won't give me an actual line. It just says:
#0 0x0000000000400b2e in repository_print ()
#1 0x0000000000400722 in main ()
Does anyone how I can find the seg fault or why the seg fault is occurring? Thanks.
EDIT:
I did try compiling with -g and found that the error is occurring at the line "while((travTemp->next)!=NULL)". This is confusing to me because this attribute should not be NULL. I'll have to check the rest of my code. The main_list declaration is as follows in case anyone needs to know:
node *main_list[MAX_HEIGHT][MAX_LEVEL];
EDIT:
So following Felipe's advice I changed my print function to the following:
node *travTemp;
travTemp = main_list[highest_level][0];
while(travTemp!=NULL && (travTemp->down)!=NULL){
printf(" {%d, %d}", travTemp->next->key, travTemp->next->d);
travTemp = travTemp->next;
}
travTemp = main_list[highest_level+1][0];
printf("\n");
However, now, I'm getting a seg fault at the print statement line. If travTemp->next does not equal NULL what's the problem with travTemp->next->key? I have no idea why since these values should exist in the repository.
If main_list[highest_level][0] is NULL, then your initial attempt to test travTemp->next will fail. #Filipe has addressed getting more debugging info in the comments.
Update: if it isn't NULL but following travTemp seems to be the problem, perhaps it is some other illegal value. Not seeing how main_list was filled, can't say more than that.
Though after writing code and examining it so many times i am getting an assertion error. i dunno why. hope you pals can help me.This is the function
int GetNth(struct node* head, int index) {
Node* current = head;
int count = 0; // the index of the node we're currently looking at
while (current != NULL) {
if (count == index)
return(current->data);
count++;
current = current->next;
}
assert(0);
// if we get to this line, the caller was asking
// for a non-existent element so we assert fail.
}
this is the error i get.
GetNth: Assertion `0' failed.Aborted (core dumped)
My doubt is that if there is a hit with the position whose value is expected, why would Assertion test happen? As there is already a return statement of the while loop which exits the function.
If i comment that assertion test and if there is a hit/miss with position whose value is expected, it returns me 0 every time instead of value/null
Thanks in advance!
I debug code like this with good old fashion printf's
int GetNth(struct node* head, int index) {
Node* current = head;
int count = 0; // the index of the node we're currently looking at
if ( index < 0 ) {
printf( "invalid -ve index passes\n" );
assert(0);
}
printf( "starting ptr %p\n", current );
while (current != NULL) {
printf( "checking value %d against %d for ptr %p", count, index, current );
if (count == index) {
printf( "found\n" );
return(current->data);
}
count++;
current = current->next;
}
printf( "not found\n" );
assert(0);
// if we get to this line, the caller was asking
// for a non-existent element so we assert fail.
}
Run it and see what you get out. If needed change the printf for fprintf( stderr.
Aside from some input/output issues, your code looks correct, I think the problem is that the list you are passing in is either NULL, or it doesn't have enough items. And so you hit the assertion failure.
Output issue - assert(0) is not a good way to return an error to a caller of a function. C language provides no way for a caller function to detect the assertion failure. So your process will crash.
Also it is likely that the reason someone is calling your API is they don't know whether the item is in the list or not, so crashing the process is not a good design from that POV.
Input issue - you don't validate the input argument is positive. Or restrict it to being unsigned.
I am creating a program in c which is based on a linked list, where every node (of struct) holds an integer and a pointer to the next node.
I use dynamic allocation (malloc) and deallocation (free) as new nodes are added and old nodes are deleted.
when a node is deleted a function named delete is called.
I discovered that the program crashes sometimes when this delete-function is called and I KNOW that its something with the pointers in the method but I dont know WHERE in the code (row number) and WHY this happends.
I am used to high-level languages such as Java and I am used to encircle the problem by putting print-syntax at certain places in the method just to reveal WHERE it crashes.
I thought I could do the same with c and with pointer because to my knowledge I beleive the code is read from top to bottom that is 1, 2, 3, 4, and so on. (maybe interrupt handlers behave another way?)
So in this function named delete I have gone so far by putting this printf() at the very beginning of the delete-function - and all the same the program crashes.
So my Question - is it really possible that its some syntax in the delete-function (when I loop pointers for instance) that causes the crash WHEN not even the printf() is printing?
Am I wrong when I believe that the program is executed from to to bottom - that is 1, 2, 3 ....
You can se my printf-function in the very beginning of delete-function
And by the way - how could I solve this problem when I get this cryptic crash message from windows? See the bitmap!!
Greatful for answers!!!
int delete(int data) {
printf("IN THE BEGINNING OF DELETE!!!");
int result = 0;
if (queueref.last != NULL) {
node *curr_ptr;
node *prev_ptr;
node *temp_ptr;
if (queueref.first->data == data) {
temp_ptr = queueref.first;
queueref.first = queueref.first->next;
destroy_node(temp_ptr);
result = 1;
if (queueref.first == NULL) {
queueref.last = NULL;
puts("queue is now empty!!!");
}
} else {
prev_ptr = queueref.first;
curr_ptr = queueref.first->next;
printf("prev_ptr: %d\n", prev_ptr);
printf("curr_ptr: %d\n", curr_ptr);
while(curr_ptr != NULL) {
if (curr_ptr->data == data) {
result = 1;
if (curr_ptr->next != NULL) {
temp_ptr = curr_ptr;
destroy_node(temp_ptr);
prev_ptr->next = curr_ptr->next;
} else {
temp_ptr = curr_ptr;
queueref.last = prev_ptr;
prev_ptr->next = NULL;
destroy_node(temp_ptr);
}
}
curr_ptr = curr_ptr->next;
prev_ptr = prev_ptr->next;
}
}
}
return result;
}
Common mistake, here's the deal. This
printf("IN THE BEGINNING OF DELETE!!!");
needs to be
printf("IN THE BEGINNING OF DELETE!!!\n");
^^ note the newline
The reason is because stdio does not flush stdout until it sees a newline. If you add that newline, you should see the printf when the code enters the function. Without it, the program could crash, the stdout buffer would not have been flushed and would not see the printf.
Your code seems to have lots of implementation flaws. As a general advice I would recommend using some standard well-tested queue support library and static code analyzers (in this case you would even find dynamic analyzer valgrind very helpful, I guess).
For example, if implementation of destroy_node(ptr) is equivalent to free(ptr), then your code suffers from referencing destroyed data (or ,in other words, garbage) in this code snippet:
while(curr_ptr != NULL) {
if (curr_ptr->data == data) {
result = 1;
if (curr_ptr->next != NULL) {
temp_ptr = curr_ptr;
destroy_node(temp_ptr);
prev_ptr->next = curr_ptr->next; //<- curr_ptr is still in stack
//or register, but curr->next
//is garbage
// what if curr_ptr is first node? did you forget to update queueref.first?
} else {
temp_ptr = curr_ptr;
queueref.last = prev_ptr;
prev_ptr->next = NULL;
destroy_node(temp_ptr);
}
// if you you need to destroy only one node - you can leave the loop here with break;
}
curr_ptr = curr_ptr->next; /// assigning garbage again if node is found
prev_ptr = prev_ptr->next;
The reason why using destroyed data can work in * most * (if I can say that, basically this is unpredictable) cases is that the chances that this memory can be reused by other part of program for dynamically allocated data can vary on timings and code flow.
PS
Regarding cryptic messages in the Windows box - when program crashes OS basically generates crashdump and prints registers (and dumps some relevant memory parts). Registers and memory dumps can show the place of crash and immediate register/stack values but you have to now memory map and assembler output to understand it. Crashdump can be loaded to debugger (WinDbg) together with unstripped binary to check stactrace and values of local variables at the moment of crash. All these I described very very briefly, you could find tons of books / guides searching for "windows crash or crashdump analysis"