Failed to use strcpy() in stack - c

this is a code about push strings and pop strings from a stack, the string name must be fixed (not input by user). But the code is unable to run (it cannot display anything). And the point is because strcpy(temp->id,val);, if i get rid of strcpy(temp->id,val);, then the code can be run properly (but printf unreadable characters). Can I know whats is the problem with my strcpy?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct LLNode
{
char id[4];
struct LLNode *next;
};
struct LLNode * createNode(char val[])
{
struct LLNode *temp;
temp=(struct LLNode *)malloc(sizeof(struct LLNode));
strcpy(temp->id,val);
temp-> id[4] = val;
temp-> next = NULL;
return (temp);
};
char push(char val[], struct LLNode *head)
{
struct LLNode *temp;
temp = createNode(val);
temp->next = head->next;
head->next = temp;
};
char pop(struct LLNode *head)
{
struct LLNode *temp;
char val;
val = head->next->id;
temp = head->next;
head->next = head->next->next;
free(temp);
return(val);
};
int main()
{
char value;
struct LLNode *head = NULL;
struct LLNode *tail = NULL;
struct LLNode *curr;
head = createNode('\0');
tail = createNode('\0');
char id[6][4] = {"A123","B234","C345","D456","E567","F678"};
int n;
for (int i=0;i<6;i++)
{
push(id[i],&head->id);
printf("%s\n",&head->id);
}
};

char id[4];
char id[6][4] = {"A123","B234","C345","D456","E567","F678"};
A string is a nul-terminated sequence of non-nul elements including the terminator.
You are always forgetting that small but significant terminator.
And while that works fine when initializing an array with explicit length with a string-literal, as in you may drop the implicit terminator that way, remember that you thereafter don't have a string.
Anyway, your nodes arrays don't take advantage of that rule, and are also too short.
struct LLNode * createNode(char val[]);
head = createNode('\0');
A function that expects a string should not be fed a single character. Worse still, '\0' is a legitimate null-pointer-literal. Even though that's not what you wanted.
temp-> id[4] = val;
Assigning a pointer to past-the-end of a character array is beyond the pale. Are you requesting warnings from the compiler, and adherence to a specific standard? For gcc / clang, I suggest at least -Wextra -std=c99 -pedantic.

Related

Building a Linked List of Strings

I had a singly linked list that took in integers successfully, but now I want to use strings. However it is not working. I am getting so many different errors about "casting". I am finding conflicting information online as well. One comment here, Creating linked list of strings, said not to use strcpy, but I see strcpy used in a few examples online.
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
struct node {
char value[];
struct node* next; // pointer of structure type
};
// set existing type, node, to the alias, node_t
typedef struct node node_t;
node_t *create_new_node(char value) {
// create space for node with malloc
node_t *result = malloc(sizeof(node_t));
// set the value of the new node
result->value = value;
//strcpy(result->value, value);
// set the value's next pointer to null
result->next = NULL;
return result;
}
node_t *insert_at_head(node_t **head, node_t *node_to_insert) {
node_to_insert->next = *head;
*head = node_to_insert;
return node_to_insert;
}
//Prints linked list
void printlist(node_t* head) {
node_t *temporary = head;
while (temporary != NULL) {
//print out the value of the node that temporary points to
// printf("%d - ", temporary->value);
// to move along the list
temporary = temporary->next;
}
printf("\n");
}
int main() {
node_t *tmp;
// declaring head pointer
node_t *head = NULL;
// CREATING LINKED LIST
// for (int i = 0; i < 25; i++) {
// tmp = create_new_node(i);
// // sending the address of the head variable
// //calling by reference
// //SINCE HEAD IS ALREADY A NODE POINTER
// insert_at_head(&head, tmp);
// }
printlist(head);
tmp = create_new_node("I like food");
insert_at_head(&head, tmp);
}
How can I get this Linked List of string to work?
Thank you.
If you reorganize it a bit, you will be able to allocate the space the struct & the place for the string in the single malloc.
struct node
{
struct node* next; // pointer of structure type
char value[];
};
// set existing type, node, to the alias, node_t
typedef struct node node_t;
node_t *create_new_node(const char *value)
{
// create space for node with malloc
node_t *result = malloc(sizeof(*result) + strlen(value) + 1);
if(result)
{
strcpy(result->value, value);
result->next = NULL;
}
return result;
}
Please use your compiler! I ran $gcc -Wall a.c on this code and got:
a.c:7:10: error: flexible array member not at end of struct
char value[];
^
a.c: In function ‘main’:
a.c:67:5: warning: passing argument 1 of ‘create_new_node’ makes integer from pointer without a cast [enabled by default]
tmp = create_new_node("I like food");
^
a.c:15:9: note: expected ‘char’ but argument is of type ‘char *’
node_t *create_new_node(char value) {
^
a.c:70:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
Now we know what the problems are. Firstly, char value[] should be char *value since it's a pointer rather than a flexible array member (FAM). You could also move the FAM to the end of the struct if you want as shown here.
Next, node_t *create_new_node(char value) is relying on a char value when you really want a string, char *value for the parameter. There are issues beyond this: you'll likely want to make a copy of the string for the node in case it disappears from the stack. This memory should be cleaned up after use.
Other tips:
Avoid noisy, redundant comments like:
// declaring head pointer
node_t *head = NULL;
malloc(sizeof(*name_of_the_var)); is safer than malloc(sizeof(node_t)); if the data changes.
node_t *insert_at_head(node_t **head, node_t *node_to_insert) modifying its parameter and returning it is a little unusual. I'd make it void to make the in-place contract explicit.
Alphabetize and remove unused imports.
Check that malloc calls succeeded.
Remember to return 0; from main.
typedef struct node node_t; is okay but also hides info--I prefer keeping the struct there.
Here's a possible rewrite:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char *value;
struct node* next;
};
struct node *create_new_node(char *value) {
struct node *node = malloc(sizeof(*node));
if (!node) {
fprintf(stderr, "%s:%d malloc failed\n", __FILE__, __LINE__);
exit(1);
}
node->next = NULL;
node->value = strdup(value);
if (!node->value) {
fprintf(stderr, "%s:%d malloc failed\n", __FILE__, __LINE__);
exit(1);
}
return node;
}
void insert_at_head(struct node **head, struct node *node_to_insert) {
node_to_insert->next = *head;
*head = node_to_insert;
}
void print_list(struct node *head) {
for (; head; head = head->next) {
printf("%s->", head->value);
}
puts("");
}
void free_list(struct node *head) {
while (head) {
struct node *tmp = head;
head = head->next;
free(tmp->value);
free(tmp);
}
}
int main() {
struct node *head = NULL;
for (int i = 0; i < 10; i++) {
char n[16];
sprintf(n, "%d", i);
insert_at_head(&head, create_new_node(n));
}
print_list(head);
free_list(head);
return 0;
}
Output:
9->8->7->6->5->4->3->2->1->0->

Segmentation Fault 11: 10

I have a problem with solving a problem. I get continue the segmentation fault: 11 error, while I try this code. And every time I change the code the error pops up, and I don't know where the flaw is, so I would be greatfull if anyone sees the flaw.
I thank you in advance.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "dbg.h"
typedef struct node{
char *data;
struct node *next;
} node_t;
node_t **push(node_t **head, char *data){
node_t *new_node;
new_node = malloc(sizeof(node_t));
new_node->data = data;
new_node->next = *head;
*head = new_node;
free(new_node);
return head;
}
int main(int argc, char *argv[])
{
node_t **head;
char *data = "hoi";
char *data2 = "hallo";
head = malloc(20 * sizeof(node_t));
head = push(head, data);
head = push(head, data2);
printf("%s\n",(*head)[1].data);
free(head);
return 0;
}
Flaws:
Your push() function assigns the value of new_node to *head, making it accessible to the invoker of push(), but at the end of the function you free new_node, making it a dangling pointer. That's a good ground for segmentation faults.
head is a pointer to a pointer but is assigned the result of a malloc() invokation that seems to indicate that it should be a pointer to a node.
Your design is confusing: do you want to allocate the memory in push() or in main(). Certainly, both is not a good choice.
You are pointing to constant strings with non constant pointers. This is dangerous. Writing to the constant strings through these pointers could lead to segmentation faults too.
Here is a version of your program that works:
#include <stdio.h>
#include <stdlib.h>
struct node {
const char *data;
struct node *next;
};
static struct node *push(struct node *head, const char *data) {
struct node *node;
node = malloc(sizeof *node);
node->data = data;
node->next = head;
return node;
}
int main(int argc, char *argv[])
{
struct node *head = NULL;
const char *data = "hoi";
const char *data2 = "hallo";
head = push(head, data);
head = push(head, data2);
struct node *node = head;
while (node) {
printf("%s\n", node->data);
node = node->next;
}
return 0;
}
Note that I implemented a LIFO structure, aka. a stack, because a push() function usually applies to a stack.
A logical next step for you would be to implement the pop() function. Typically, I would recommend that pop() frees the node and returns the data. That would provide a nice symmetry for your API.

why do we use pointer to a pointer

#include <stdio.h>
#include <stdlib.h>
struct llnode {
int data;
struct llnode *next;
};
void insert (struct llnode **head, int data);
int
main () {
struct llnode *head;
head = NULL;
printf("starting\n");
insert(&head, 4);
return 0;
}
void
insert (**struct llnode **head**, int data) {--> why do we use a pointer to a pointer
printf("insert %0d\n", data);
struct llnode *l = malloc(sizeof(struct llnode));
l->data = data;
l->next = NULL;
if (*head == NULL) {
*head = l;
} else {
struct llnode *tmp = *head;
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = l;
}
}
1)Why do we use a pointer to pointer. Can it be explained with an example.
2)How to do insertion into a doubly linked list?
HElp me and please explain how to print
Often a pointer to pointer is used when you want to pass to a function a pointer that the function can change.
Pointer to pointer or double pointer are variables whose possible values ​​are memory addresses of other pointer variables.
You have a good answer here, I think he can explain it better than me.
Also you can check this link.

Casting items to end of linked list in C

EDIT*(8:14 PM) - Sorry I corrected my code and made this instead a method so it can be more easily understood.
I am not sure how to properly cast a struct when adding to the end of a linked list. Compiling this code gives me an cast warning at the very last line. This may be the reason why the rest of my code does not properly function.
For example:
#include <stdlib.h>
typedef struct {
int data;
struct node *next;
} node;
node *HEAD = NULL;
node *addNode(int num)
{
if (HEAD == NULL) {
HEAD = (node *)malloc(sizeof(node));
HEAD->next = NULL;
HEAD->data = num;
}
else {
node *newNode;
newNode = (node *)malloc(sizeof(node));
newNode->data = num;
newNode->next = NULL;
node *iter;
iter = (node *)malloc(sizeof(node));
iter = (node *)HEAD;
while(iter->next != NULL)
iter = (node *)iter->next;
iter->next = newNode; //warning : warning: assignment from incompatible pointer type
}
return HEAD;
}
Make sure to include stdlib.h -- needed to use malloc
fix all occurance of wordNode to be node -- wordNode is undefined in your program
create a struct and typedef both named node -- standard trick for self referential structs
and then all your warnings goes away;
#include <stdlib.h>
struct node{
int data;
struct node *next;
};
typedef struct node node;
node *HEAD = NULL;
int main(int argc, char*argv[]) {
int x = 1;
int y = 2;
if(HEAD == NULL)
{
HEAD = (node *)malloc(sizeof(node));
HEAD->next = NULL;
HEAD->data = x;
}
else
{
node *newNode;
newNode = (node *)malloc(sizeof(node));
newNode->data = y;
newNode->next = NULL;
node *iter;
iter = (node *)malloc(sizeof(node));
iter = (node *)HEAD;
while(iter->next != NULL)
iter = (node *)iter->next;
iter->next = newNode; //warning : warning: assignment from incompatible pointer type
return 0;
}
}
The problem is that you declare "next" to be a pointer to "struct node" before the struct is completely defined, so "next" points to an undefined structure. If you change "typedef struct{" to "typedef struct node{", that error will be gone.
There is a number of problems with your code. The first one would be casting the return value of malloc and improperly referring to the size of the type for which you want some space to be allocated :
HEAD = (node *)malloc(sizeof(node));
should be replaced by
HEAD = malloc(sizeof(*HEAD))
Since the conversion from void* to any other type is always defined and implicit in C, you don't get any warnings about a needed cast. Specifying sizeof(*HEAD) makes the compiler automatically choose the type of HEAD at compile time, thus reducing the needed work should the type ever change.
You should also remember that some compilers don't like anonymous structures (i.e. structures without a name declared). Therefore, the code
typedef struct{
int data;
struct node *next;
} node;
should be replaced by
typedef struct _node {
int data;
struct _node *next;
} node;
Which declares a structure called _node, typedefed to the type called node. And also fixes the circular reference.
On top of all that, you don't need to malloc any space for the iter.

Double linked list; newbie attempt

I've just started out learning C, and (seemingly) so far most stuff is clicking. However, I'm having some trouble tracking down an issue with an attempt at a double linked list. I keep getting a seg-fault when I attempt to build/run this code. I'm compiling with the Cygwin supplied gcc via NetBeans.
I hate to just dump a block of code and say "help", but I don't know what other details are pertinent at this time, so feel free to ask for details if necessary:
#include <stdio.h>
#include <stdlib.h>
struct node_t{
struct node_t *prev;
struct node_t *next;
};
struct list_t{
struct node_t *head;
struct node_t *tail;
int length;
};
struct node_t *new_node(void);
struct list_t *new_list(void);
int append_list_node(struct list_t *list, struct node_t *node);
int main(void) {
int i = 0, length = 0;
struct node_t *node;
struct list_t *list = new_list();
for(i = 0; i < 10; i++){
length = append_list_node(list, new_node());
printf("%d", length);
}
return 0;
}
struct node_t *new_node(void){
struct node_t *node = malloc(sizeof(struct node_t));
return node;
}
struct list_t *new_list(void){
struct list_t *list = malloc(sizeof(struct list_t));
list->length = 0;
return list;
}
int append_list_node(struct list_t *list, struct node_t *new_node){
if(list->head == NULL){
list->head = new_node; // edited
new_node->prev = NULL;
}else{
list->tail->next = new_node;
new_node->prev = list->tail;
}
return (++list->length);
}
Thanks for the super quick responses everyone, all the answers are correct. As I was briefly looking over the code between F5-ing, I realized I wasn't setting the tail, so I resolved to change the line marked edited as follows:
list->head = list->tail = new_node;
I'll also resolve to use calloc() however, I've read that frequent use of it can cause considerable costs to execution time since it's clearing and allocating. Thoughts?
Use calloc() to allocate memory. The malloc() function does not initialize the memory to zeros (so the pointers will be set to NULL). You are making the assumption that the pointers are NULL by default.
C doesn't do any initialization for you. So when you do:
struct list_t *new_list(void){
struct list_t *list = malloc(sizeof(struct list_t));
list->length = 0;
return list;
}
list->head can be anything.. and probably won't be NULL.
One issue is that you never set list->tail to anything, and then attempt to access list->tail->next if list->head isn't NULL (which, as other have pointed out, isn't guaranteed anyway.)

Resources