making a pointer that stores an element of a char array - c

I've been struggling trying to figure out why I am getting the following warning:
initialization makes pointer from integer without a cast
The highlighted warnings are where I mentioned below. The code I am currently using is just the beginning of creating tree of elements in a linked list fashion. This code seems to be working fine however I get docked points for warnings.
typedef struct Node {
struct Node *leftChild;
struct Node *rightChild;
char data;
} Node;
Node *TreeCreate(int level, const char *data) {
struct Node *ptr = (struct Node*) malloc(sizeof (Node));
if (ptr == NULL) {
// malloc failed
return 0;
}
ptr->data = data; // WARNING
ptr->leftChild = NULL;
ptr->rightChild = NULL;
return ptr;
}
// TEST CODE IN MAIN
char list[6] = {'A', 'B', 'C','\0'};
// Determines the element
const char *tree = list[0]; // WARNING
ptr = TreeCreate(1, tree);
if (ptr != NULL) {
sprintf(string, "TreeData: %c\n", ptr->data);
OledDrawString(string);
OledUpdate();
}

Your fundamental mistake is that you are assigning a poitner to a char which is wrong
const char *tree = list[0]; // WARNING
this will not yield the result you expect.
The * in this case is not dereferencing the pointe, you are declaring a poitner and pointeing to a char with it, then when you try to access the pointer, your program tries to read at an invalid memory address causing undefined behavior.
Then you do the opposite thing in
ptr->data = data;
you should enable compiler warnings to avoid this mistakes.
To handle the data you apparently want to handle, first you need to redefine the struct like this
typedef struct Node {
struct Node *leftChild;
struct Node *rightChild;
char *data;
/* ^ this should be a char pointer */
} Node;
then in the TreeCreate() function, copy the data by first allocating space and then using memcpy() like this
Node *TreeCreate(int level, const char *data) {
size_t length;
struct Node *ptr;
ptr = malloc(sizeof (Node));
if (ptr == NULL) {
return NULL;
}
if (data != NULL)
{
length = strlen(data);
ptr->data = malloc(1 + length);
if (ptr->data != NULL)
memcpy(ptr->data, data, 1 + length);
}
else
ptr->data = NULL;
ptr->leftChild = NULL;
ptr->rightChild = NULL;
return ptr;
}

I think I understand. The following fixed my warnings. Thanks for the fast response!
const char *tree = &list[0];
ptr->data = *data;

the following, a complete program,
that cleanly compiles
and has the warnings fixed
and eliminates the clutter and unnecessary typedef statements.
#include<stdio.h>
#include<stdlib.h>
struct Node
{
struct Node *leftChild;
struct Node *rightChild;
char data;
};
struct Node *TreeCreate(int level, const char *data)
{
struct Node *ptr = malloc(sizeof (struct Node));
if (ptr == NULL)
{
// malloc failed
return NULL ;
}
// implied else, malloc successful
ptr->data = *data; // WARNING
ptr->leftChild = NULL;
ptr->rightChild = NULL;
return ptr;
}
int main()
{
struct Node *ptr = NULL;
char string[120] = {'\0'};
// TEST CODE IN MAIN
char list[6] = {'A', 'B', 'C','\0'};
// Determines the element
const char *tree = &list[0]; // WARNING
ptr = TreeCreate(1, tree);
if (ptr != NULL)
{
sprintf(string, "TreeData: %c\n", ptr->data);
//OledDrawString(string);
//OledUpdate();
}
return 0;
}

Related

segmentation fault for a bool function that's adds students to a linked list

my assignment is to create a linked list and then write a bool function attempts to add a student with given id and name into the given list; if a student with that id is already in the list then return false, otherwise the list is modified and true is returned. Im a beginner and I rarely understand why segmentation faults occur so any help will be appreciated.
here are my structure definitions(provided by prof)
struct snode{
int id;
char * name;
struct snode * next;
};
struct slist{
struct snode * front;
};
here is my bool function
bool insert_student(int id, char name[], struct slist * lst) {
struct snode *head = malloc(sizeof(struct snode));
head = lst->front;
// check if list is empty
if (head != NULL) {
struct snode *node = malloc(sizeof(struct snode));
while (node != NULL) {
// traverse the list to see if student exists in list
if (node->id = id) {
return 0;
}
else {
// if it doesnt exist, add it
struct snode *ins_std = malloc(sizeof(struct snode));
ins_std = node->next;
ins_std->id = id;
ins_std->name = name;
ins_std->next = lst->front;
lst->front = ins_std;
return 1;
}
node = node->next;
}
} // if list is empty
else {
head->next = NULL;
head->name = name;
head->id = id;
return 1;
}
}
main function
int main() {
struct slist *head = create_list();
int id1 = 11001;
int id2 = 11002;
int id3 = 11003;
int id4 = 11004;
int id5 = 11005;
char name1[] = "Dave";
char name2[] = "Ali";
char name3[] = "John";
char name4[] = "Randall";
char name5[] = "Kelly";
assert(insert_student(id1, name1, head) == 1);
insert_student(id2, name2, head);
insert_student(id3, name3, head);
insert_student(id4, name4, head);
insert_student(id5, name5, head);
}
Im a beginner and I rarely understand why segmentation faults occur I suspect you never do at this stage.
struct snode *head = malloc(sizeof(struct snode));
head = lst->front;
Here you allocated some space and save the reference to head, only to be overwritten by lst->front (which could be NULL). These two lines already cause segfault. I think what you are trying to do is to save the reference to the allocated space to lst->front, namely lst->front = head; instead of the other way around.
if(node->id = id){
Common error, use == for equality check.
struct snode *ins_std =malloc(sizeof(struct snode));
ins_std = node->next;
Similar issue to the first code snippet.
Solving the above issues should fix the segfaults and assertion errors. There are also a few logical loopholes in the code, but that is for another story.
As a beginner, it helps to have "working code" to study. Here's a 'stripped down' version of your assignment. Make sure you understand what it does, then gradually add elaborations to build-up toward the entire project.
Programs aren't "typed-in", straight from brain to keyboard. You start off with something simple, then SLOWLY embellish that. Compile (with warnings turned up to the max) often, and test each step along the way.
Best wishes.
struct snode{
int id;
struct snode * next;
};
bool addNode( struct snode **pList, int id ) {
for( struct snode *pSrch = *pList; pSrch; pSrch = pSrch->next )
if( pSrch->id == id )
return false; // already on list...
struct snode *pNew = malloc( sizeof( *pNew ) );
// check of malloc() success omitted
pNew->id = id;
pNew->next = *pList; // PREpending to existing list
*pList = pNew;
return true;
}
int main() {
int ids[] = { 11001, 11002, 11003, 11004, 11005, 11002, 11006, 11007, }; // Notice blooper
const int nIDs = sizeof ids/sizeof ids[0];
struct snode *pList = NULL; // This will be 'buried' as "front"...
for( int i = 0; i < nIDs; i++ ) {
printf( "ID %d ... ", ids[i] );
if( addNode( &pList, ids[i] ) )
printf( "Success\n" );
else
printf( "Failed\n" );
}
for( struct snode *pWalk = pList; pWalk; pWalk = pWalk->next )
printf( "Walking... ID %d\n", pWalk->id );
return 0;
}
There are several mistakes in the code shown.
Here is a cleaned up example.
Within insert_student we:
Immediately check that lst is not NULL. If it is, we immediately return false. Every point in the function afterward we can assume lst is not NULL.
Create a pointer to a node that will point to the last node in the list.
If the front node in the list is not NULL we proceed to check if the node is the last. If it is, store a pointer to it in last. And if the id is already taken, we immediately return false.
Now we allocate a new node, making sure to allocate space for the name (and the null terminator character), and using strcpy to copy the name argument into the memory we've just allocated.
If last was assigned something other than NULL, have its next pointer point to the new node.
If last is still NULL it stands to reason lst->front was NULL. Assign the new node pointer to that pointer.
If execution has reached this point, the insertion has happened. Return true.
A further exercise would be to write a function to free the allocated memory.
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
struct snode {
int id;
char *name;
struct snode *next;
};
struct slist {
struct snode *front;
};
bool insert_student(struct slist *lst, int id, const char *name);
int main() {
struct slist *lst = malloc(sizeof(struct slist));
insert_student(lst, 1, "Bob");
insert_student(lst, 2, "Dave");
for (struct snode *cur = lst->front; cur; cur = cur->next) {
printf("%2d, %s\n", cur->id, cur->name);
}
return 0;
}
bool insert_student(struct slist *lst, int id, const char *name) {
if (!lst) return 0;
struct snode *last = NULL;
if (lst->front) {
for (struct snode *cur = lst->front; cur; cur = cur->next) {
if (cur->next == NULL) last = cur;
if (cur->id == id) return 0;
}
}
struct snode *new_node = malloc(sizeof(struct snode));
new_node->id = id;
new_node->name = malloc(strlen(name) + 1);
strcpy(new_node->name, name);
if (last) {
last->next = new_node;
}
else {
lst->front = new_node;
}
return 1;
}
Output:
1, Bob
2, Dave

C Segmentation Fault (core dumped) Linked List

I keep getting Segmentation Fault (core dumped) run time error and I can't figure out why.
My code:
struct Node
{
void *next;
void *val;
};
typedef struct Node* NodePtr;
struct List
{
NodePtr head;
};
typedef struct List* ListPtr;
ListPtr create()
{
ListPtr ptr = malloc(sizeof(struct List));
return ptr;
}
int insert(ListPtr list, void *obj)
{
NodePtr newObj = malloc(sizeof(struct Node));
//Cast next as a self referencing Node
newObj->next = (NodePtr) newObj->next;
//Point to beginning of list
NodePtr current = list->head;
if(list->head == NULL)
{
newObj->val = obj;
list->head->next = newObj;
newObj->next = NULL;
return 1;
}
return 0;
}
int main(int argc, char *argv[])
{
int x = 2;
int *p = &x;
ListPtr thing = create();
insert(thing, p);
return 0;
}
The error is here: list->head->next = newObj after some debugging. I thought I had to allocate memory for list->head->next, but when I added the code in for that it still gave me the same error. Am I casting it wrong or not allocating memory correctly? Any help would be appreciated, thanks!
Just put this together, runs fine.
#include <stdlib.h>
#include <stdio.h>
struct Node {
void *next;
void *val;
};
typedef struct Node* NodePtr;
struct List {
NodePtr head;
};
typedef struct List* ListPtr;
ListPtr CreateList() {
ListPtr ptr = malloc(sizeof(struct List));
return ptr;
}
void Insert(ListPtr list, void *obj) {
// create and initialize new node
NodePtr newObj = malloc(sizeof(struct Node));
newObj->val = obj;
newObj->next = NULL;
//Point to beginning of list
NodePtr curr = list->head;
// Add node to the list
if(curr == NULL) // if no head node, make newObj the head node
{
list->head = newObj;
}
else{ // otherwise traverse the list until you find the last node (the one that points to a null as the next)
while(1) {
if(curr->next != NULL) {
curr = curr -> next;
} else {
curr->next = newObj;
}
list->head = newObj;
newObj->val = obj;
list->head->next = newObj;
newObj->next = NULL;
}
}
}
int main() {
int x = 2;
int *p = &x;
ListPtr thing = CreateList();
Insert(thing, p);
return 0;
}
You check if list->head is NULL and then do some operations with that. Change that to if(list->head != NULL)
{
...
}
At a thought, malloc does not guarantee allocated memory is empty. It's good practice to set all values where they matter after allocation.
list->head is probably not null
also : newObj->next = (NodePtr) newObj->next;
doesn't set to a rational value, it sets to whatever memory was set - were you intending newObj->next = (NodePtr) newObj; ?
list->head should not be referenced if null. list->head->next will only be valid if it's not null.
if you actually want to build a list,
newObj->val = obj;
if (list->head == NULL) { newObj->next = list->head; }
list->head = newObj;
either that or travel down list->head->next chain until next is null, and set that to be newObj->next. If that way then it's possibly a good idea, newObj->next should be set to NULL and not itself.
Might want to figure out how your list will behave - is it circular? does it grow from the head (list->head) or tail (last ->next) ? Do you spot the tail when listObject->next == NULL or when listObject->next == listObject ?
I realize that this answer is mostly stylistic. But I do think that (bad) style and (bad) habits are an (important) part of (bad) programming. Summing it up ...
(in most cases) typedefs are not needed; they just introduce an alias for something that already existed.
[rule of seven] human readers have a limited amount of identifiers ("names") that they can keep track of. This could be 7. Minimising the number of distinct words makes reading easier.
also, the reader has to remember that xPtr and xNode are related (typeof *xPtr === typeof xNode)
when reading source code, keywords and special character tokens (such as operators) don't count as an identifier, since you do not have to remember them. (Syntax-highligting helps, too)
if there is only one way of expressing your program, there is no possibility for errors like iPtr *p; p = (qPtr) malloc (sizeof xNode);
creating yet another struct (+typedefs for it), just to accomodate a root pointer will clobber up your mental namespace even more.
Now a rework of the (intended) code:
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node *next;
void *payload;
};
struct node *root=NULL;
void initialize() { /* nothing .... */ }
int insert(struct node **pp, void *pv) {
struct node *p;
p = malloc(sizeof *p);
if (!p) { /* handle error */ return -1; }
p->payload = pv;
p->next = *pp;
*pp = p;
return 1; /* inserted one element */
}
int main(void)
{
int i;
i=666;
/* note: this function call will pass a pointer to a local variable `i`
** to the insert() function, which will remember it.
** This is generally a bad idea, to say the least.
*/
insert( &root, &i);
return 0;
}

Simple malloc function in c

#define SIZE 7000
static char buf[SIZE];
static char *bufptr = buf;
struct node
{
int reg_num;
int val;
char var_name[30];
char var_str[100];
struct node *memroy;
struct node *next;
};
struct node* add(struct node *head, int i)
{
struct node *temp;
if (head == NULL)
{
temp = (struct node *)malloc(sizeof(struct node));
temp->next = NULL;
temp->reg_num = i;
head = temp;
}
else
{
head->next = add(head->next, i);
}
return head;
}
void* malloc(int n)
{
if (buf + SIZE - bufptr >= n)
{
bufptr += n;
return bufptr - n;
}
else
{
return NULL;
}
}
When I run my programm it crashes during the assignment temp->next = NULL.
I think the problem is in my malloc function. I tested it with malloc in libraries and it worked correctly, but I not allowed to use libraries and must write a new malloc function.
You never check the return of your malloc yet you know it can return NULL;.
Check if temp is NULL before doing temp->next = NULL;
My problem don't has relation with kind of pointer and returned value from malloc().I have problem with size of buf[] and by increment of size my problem solved.Tnx from every one.

singly linked list error while adding a node

My problem is that, when i try to add a node to my singly linked list for the first time, everything goes expected, but when i want to add another node, my program crashes. Seems like my error is caused by trying to write to 0 address. however i can't seem to find the error in my code. am i using malloc right ?
Here is the code :
typedef struct linkedList
{
int StudentId;
char name[100];
char dep[100];
struct linkedList *next;
} LinkedList;
LinkedList *head = NULL;
LinkedList *current = NULL;
LinkedList *createList(int val, char name[], char dep[])
{
LinkedList *ptr = (LinkedList *)malloc(sizeof(LinkedList));
if (ptr == NULL)
{
printf("Node Creation Failed\n");
return NULL;
}
ptr ->StudentId = val;
strcpy(ptr -> name, name);
strcpy(ptr ->dep, dep);
ptr ->next = NULL;
head = current = ptr;
return ptr;
}
LinkedList *addToList (int val, char name[], char dep[])
{
if (head == NULL)
{
return (createList(val, name, dep));
}
else
{
LinkedList *ptr = (LinkedList *)malloc(sizeof(LinkedList));
if (ptr = NULL)
{
printf("Node Creation Failed\n");
return NULL;
}
ptr -> StudentId = val;
strcpy(ptr ->name, name);
strcpy(ptr ->dep, dep);
ptr -> next = NULL;
current -> next = ptr;
current = ptr;
return ptr;
}
}
in main function:
AddtoList(10,"abc","abc");
calls createList, no problem but
If i use AddtoList again, program crashes, createList and AddtoList are really similar to each other, can't figure out what the problem is.
Change
if (ptr = NULL)
to
if (ptr == NULL)
In your case, ptr is assigned to NULL and expression within if is evaluated to 0. Control goes to ptr -> StudentId = val;. It tries to access write protected memory, hence the crash.

Struct Pointers on a Linked List Implementation

I'm working on a linked list implementation in C to get the hang of pointers and structs. Here is the basic code for my LL data structure:
struct Node {
void *data;
struct Node *next;
};
struct List {
struct Node *head;
};
void initList(struct List *list) {
list->head = 0;
}
struct Node *addFront(struct List *list, void *data) {
struct Node *newNode;
newNode->data = data;
newNode->next = list->head;
list->head = newNode;
return newNode;
}
Here is the test I run on it in the int main() function:
int main() {
/* test addFront */
double *data1;
double *data2;
*data1 = 10.5;
*data2 = 10.7;
struct List *newList;
initList(newList);
addFront(newList, data1);
printf("%s\n", newList->head->data);
addFront(newList, data2);
printf("%s\n", newList->head->data);
return 0;
}
My problem is that printf is not printing the output. As it stands now, it obviously doesn't print because %s doesn't match the data type, which is double. If I change the string format to %d, it gives me a segmentation fault. If I add a (double) cast, it says that the second argument has type double *, which confuses me because I thought the -> notation dereferenced a pointer.
I'm lost.
You are dereferencing data1 and data2 without assigning memory to them. Try:
double data1 = 10.5;
addFront(newList, &data1);
Alternatively you could do a malloc, although I don't think you should in this case.
Also, when you want to print them, try:
printf("%f\n", *(double *)newList->head->data);
You are not allocating memory for your double pointers data1 and data2.
Looks like, actually, you're not allocating memory for nearly any of your pointers.
All a pointer does by itself is reference an address in memory. It does not allocate the memory necessary to support the referenced structure or variable.
If you have
double *data1; // or any other kind of pointer
you need something like
data1 = (double *) malloc(sizeof(double));
THEN you can dereference all you like, eg
*data1 = 12.34;
But without that, your referencing a pointer to the Black Hole of Calcutta.
In addition to the 2 printf("%f") there are 4 malloc's missing:
I marked the changed lines with ###:
#include "stdlib.h"
#include "stdio.h"
struct Node {
void *data;
struct Node *next;
};
struct List {
struct Node *head;
};
void initList(struct List *list) {
list->head = 0;
}
struct Node *addFront(struct List *list, void *data) {
struct Node *newNode = malloc(sizeof(struct Node)); //###
newNode->data = data;
newNode->next = list->head;
list->head = newNode;
return newNode;
}
int main() {
/* test addFront */
double *data1 = malloc(sizeof(double)); //###
double *data2 = malloc(sizeof(double)); //###
*data1 = 10.5;
*data2 = 10.7;
struct List *newList = malloc(sizeof(struct List)); //###
initList(newList);
addFront(newList, data1);
printf("%f\n", *(double*)newList->head->data);//###
addFront(newList, data2);
printf("%f\n", *(double*)newList->head->data);//###
// TODO: free()'s //###
return 0;
}
What have you done to try to deal with the problem?
try using "assert.h" to ensure your assertions are right, or if statements with puts/exit.
In particular, if it doesn't print something, clearly what your are printing is not what you want to print, so somewhere along the lines, an assertion must fail, and your mind will "click" where you missed a step.
The reason I can't do this immediatly is because I am not you and I do not know what assertions you are making, so it will take me longer to place them than you would.
Also, as pointed above, you are not allocating memory for newNode, and accessing arbitrary memory, which is causing segmentation fault.
There I fixed it.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
struct Node {
void *data;
struct Node *next;
};
struct List {
struct Node *head;
};
void initList(struct List **newList)
{
struct List* tmpList = 0;
assert(newList != 0);
tmpList = (struct List*)malloc(sizeof(struct List*));
assert(tmpList != 0);
tmpList->head = 0;
*newList = tmpList;
}
void addFront(struct List* list, void* data)
{
struct Node* currNode = 0;
struct Node* prevNode = 0;
assert(list != 0);
assert(data != 0);
currNode = list->head;
while (currNode != 0) {
prevNode = currNode;
currNode = currNode->next;
}
if (prevNode == 0) {
list->head = (struct Node*)malloc(sizeof(struct Node));
list->head->data = data;
list->head->next = 0;
} else {
prevNode->next = (struct Node*)malloc(sizeof(struct Node));
prevNode->next->data = data;
prevNode->next->next = 0;
}
}
void test(const struct List *list)
{
const struct Node *iter;
assert(list != 0);
assert(list->head != 0);
iter = list->head;
while (iter != 0) {
assert(iter->data != 0);
printf("%f\n", *((double*)iter->data));
iter = iter->next;
}
}
int main()
{
double* data1 = (double*)malloc(sizeof(double));
double* data2 = (double*)malloc(sizeof(double));
*data1 = 10.5;
*data2 = 10.7;
struct List* newList = 0;
initList(&newList);
assert(newList->head == 0);
puts("pass[0].");
addFront(newList, data1);
assert(newList->head != 0);
assert(newList->head->data == data1);
puts("pass[1].");
addFront(newList, data2);
assert(newList->head != 0);
assert(newList->head->data == data1);
assert(newList->head->next != 0);
assert(newList->head->next->data == data2);
puts("pass[2].");
test(newList);
return 0;
}

Resources