I made a list to do some data treatment and I'm having an issue that I don't find the cause, for me my code seems right but there are issues.
What I'm trying to do is the following :
I have a list that contains x elements. I want to add an element p in the list then take every x element, add p to the string they represent, and add them to the list. (the list by itself works great it's just that operation that causes troubles).
The problem is that when I do that and when I try to display the list the first x+p elements are displayed well, but after I see some strange characters that have nothing to do with the inputs.
Here are the functions I use :
void addFirst(struct list *l, char *key)
{
struct node *x = createNode(key) ;
if (l->size == 0)
{
l->first = x;
}
else
{
x->next = l->first;
l->first = x;
}
l->size++;
return;
}
void showList(struct list* l)
{
struct node *p=l->first;
while (p!=NULL)
{
printf("%s \n",p->key);
p=p->next;
}
return;
}
void copyPlus(struct list* l,char *ch)
{
struct node *p=l->first;
addFirst(l,ch);
while (p!=NULL)
{
int len1=strlen(p->key);
char cat[len1+2];
strcpy(cat,p->key);
strcat(cat,ch);
cat[len1+1] = '\0';
printf("[%s] \n",cat);
addFirst(l,cat);
printf("{%s} \n",l->first->key);
p=p->next;
}
return;
}
int main()
{
struct list *A=createList();
addFirst(A,"1");
addFirst(A,"2");
addFirst(A,"4");
copyPlus(A,"3");
printf("=%s= \n",A->first->key); //this one works!
printf("=%s= \n",A->first->next->key);
printf("=%s= \n",A->first->next->next->key);
showList(A);
deleteList(A);
}
I skipped the irrelevant stuffs, it's a classic list.
Node is defined that way :
struct node
{
struct node *next;
char *key;
};
After further ivestigation it appears that the process is working correctly (the two //printf in copyPlus work the way they should). And the last //printf doesn't display anything, even if I do A->first->next->next->next.
It shows 3 if I do A->first->next->next->next->next.
I really don't understand and it's starting to get on my nerves, the code is simple and short and I'm still not seeing the mistake.
Could someone help me? Thanks.
Ok, so strcat adds a terminating zero to the string, you need space for one more char. strlen will give you 1, you will allocate a char array with size 2. That's not enough - you need at least 3 for the first char, second char and terminating zero. That's still dangerous, as you don't know the length of the second string. The best solution is thus char* cat = malloc(len1 + len2 + 1).
The current problem is that char cat[len1+2]; is allocating space on the stack (that's where local function variables reside). You're basically keeping a pointer to an address inside of a stack frame, which gets destroyed after the function has finished. The first value works, because this was your last function call and still noone has decided to overwrite this memory (but anyone is free to do so). Allocating with malloc() will allocate on the heap and the value will be available until you explicitly call free.
After modifications output is:
[43]
{43}
[23]
{23}
[13]
{13}
=13=
=23=
=43=
13 23 43 3 4 2 1
A C++ solution can be found at http://pastebin.com/xNzyLQ2N .
Related
I've been learning programming for some while now and I've seen this concept of "linked list" a few times and decided to give it a try:
#include <stdio.h>
#include <stdlib.h>
typedef struct cell {
int number;
struct cell* next;
} cell;
typedef struct {
cell* head;
} cell_list;
void push_front(cell_list* list, int number) {
printf("here\n");
cell* n;
printf("here2\n");
n->number = number;
printf("here3\n");
n->next = list->head;
printf("here4\n");
list->head = n;
}
int main(int argc, char* argv[]) {
cell_list* L;
push_front(L, 5);
push_front(L, 8);
push_front(L, 19);
cell* n = L->head;
// this should print "19 8 5"
while(n != NULL) {
printf("Val: %d\n", n->number);
n = n->next;
}
return 0;
}
output:
here
here2
here3
Segmentation fault: 11
I am looking for an answer to the following two questions:
(1) What is the correct way of doing this
(2) What is actually happening in my example? What is going wrong?
I am thinking that it is the compiler that fails to assign "struct cell* next" to be equal to "cell* head", etc.) OR that the FIRST allocated memory for head and the fist cell with the next property is at fault here.
Also similar posts and questions have answer to questions identical to mine however they fail at multiple points:
(1) the code example posted by OP is overly complex
(2) the code answers are good but... check 3
(3) the code answers and not explained, just "omg just use malloc you are casting voids everywhere"
(4) 1 - 3 results in a complete post with Q&A that is above my level. If your answer is "use malloc" or "the pointers point at random memory" or "you are pointing at null". Please explain because these are just programming jargon/language sentences that don't actually go into depth so that I, a beginner, can understand.
I am fully aware there are identical posts but none truly explain to a beginner like me why they allocate memory will malloc and cast the allocated space to become a linked list struct. If your answer is the same as in any of those posts, then please explain why this way is faulty and not just "This is how you do, there are 12893 posts about malloc and linked lists." I understand malloc and casting if that was not obvious but not how they properly fit in here and how my current program is created on the stack.
In the function push_front,
cell* n;
is a pointer of type cell and as David C Rankin rightly said it is uninitialized and currently holds an indeterminate address as its value until you initialize it by assigning a valid address. It does not point to a memory of type cell just like that until you make it point to a cell type.
Use malloc to allocate memory. You can refer the manual page for malloc.
cell *n= malloc(sizeof(cell));
The very next thing your code should do is to check if call to malloc has successfully allocated memory or not and some error handling if memory is not allocated.
if(NULL == n)
{
//! handle memory allocation error here
}
You also need to free this memory once you are done using it, and make the pointer point to null.
free(n);
n = NULL;
Based on your critical rant/comment at the end of original post, let me explain the code you wrote to you.
void push_front(cell_list* list, int number)
{
/// This print helps you understand where the code is.
printf("here\n");
/// This declares is a pointer variable pointing to a `cell` type.
/// Not yet pointing since not initialized.
cell* n;
/// This print helps you understand where the code is.
printf("here2\n");
/// Tries to assign value of 'number' to 'number' variable present in
/// some memory accessed as data type `cell` via a pointer.
/// But wait, is pointer really pointing to a valid memory location
/// that can be access as `cell` type? NO!
n->number = number; // You try to sit in a chair which isn't there, you fall!
printf("here3\n");
n->next = list->head; // You try to sit on a chair which isn't there, you fall!
printf("here4\n");
list->head = n; // This is a different problem as of now.
// With 'n' not initialized, list->head also get
// corrupted since assigned with a garbage value.
}
Also, in your main() function,
cell_list* L;
and then you invoke
push_front(L, 5);
In this function, you do the following:
n->next = list->head;
You design does not consider if list->head is initialized or not. If it is NULL you just made n->next point to NULL.
I understand and agree to the fact that a lot of people find pointers hard to understand and use correctly. I'll suggest that you first get comfortable with pointers overall (in general) and then go for implementing data structures with them. We all started there! You can start here.
You have to allocate memory for nodes using malloc.
Here is the updated code, I have tested it, it is working fine :)
#include <stdio.h>
#include <stdlib.h>
typedef struct cell {
int number;
struct cell* next;
} cell;
typedef struct {
cell* head;
} cell_list;
void push_front(cell_list* list, int number) {
printf("here\n");
cell* n = malloc(sizeof(cell));
printf("here2\n");
n->number = number;
printf("here3\n");
n->next = list->head;
printf("here4\n");
list->head = n;
}
int main(int argc, char* argv[]) {
cell_list* L = malloc(sizeof(cell_list));
push_front(L, 5);
push_front(L, 8);
push_front(L, 19);
cell* n = L->head;
// this should print "19 8 5"
while(n != NULL) {
printf("Val: %d\n", n->number);
n = n->next;
}
return 0;
}
I am having problem storing all the values into the Generic LinkedList, my linkedlist works totally works on a normal user Keyboard input but when I try to store values(strings) from a file, there is something weird happening, it only store the last value of the file.
I have checked my addToList() function but theres nothing wrong with it.
P.s But I am feeling its either I am printing wrong or my reading from the file into the linkedlist is wrong.
Thank you.
#include<stdio.h>
#include <stdlib.h>
#include<string.h>
#include "LinkedListItems.h"
#define MAX 10000
int main()
{
printf("Testing MissileFIle.txt");
void* secondStr;
//Had to malloc the thing
secondStr = (void*)malloc(1*sizeof(char));
FILE* missileFile;
missileFile = fopen("missiles.txt", "r");
if(missileFile == NULL)
{
printf("The file is empty");
}
number_list_t* missileList = calloc(1, sizeof(number_list_t));
void* input;
//Have to allocate the input
input = malloc(1*sizeof(void*));
//this is to read the data into the second Str
while(fgets(secondStr,MAX,missileFile) != NULL)
{
//Let just print out first just to test my memory
printf("%s\n",secondStr);
//Right now its only reading one string so far which is really weird AFFFFF
addTolist(missileList,secondStr);
}
//Gotta declare another list just to print out the list
number_node_t* current = missileList->head;
while(current != NULL)
{
//There is something wrong with this line
printf("%s\n",current-> number);
current = current-> next;
}
fclose(missileFile);
}
OUTPUT:
Testing MissileFile.txt
splash
single
V-line
h-line
Single
Single
Single
Single
Single
Single
typedef struct NumberNode
{
//It can store any data type
void* number;
struct NumberNode* next;
}number_node_t;
//List of Nodes
typedef struct NumberList
{
number_node_t* head;
int count; //This is not nesssary but it can be useful for counting how many variables
}number_list_t;
void addTolist(number_list_t* list, void* newNumber)
{
//tem[ = newNode]
number_node_t* newNode = calloc(1,sizeof(number_node_t));
newNode->number = newNumber;
newNode->next = list->head;
list->head = newNode;
}
INPUT DATA:
single
splash
single
V-Line
h-line
Single
The way you have implemented this, it cannot work.
The main problem, among many, is related to the void* pointers which cannot be dereferenced.
The size of elements should be given, either on creating the list in which case all elements are of the same type, or separately for each individual element. You can check out this question for an example of something that could work.
As far as the buffer thing is concerned, addToList should allocate new memory for each newNumber. What you are currently doing results in all data of the list pointing to a specific space in memory (the one allocated to secondStr). Each time you change the content of that memory space, all elements in the list are affected. This is why you print the same value for all elements and more specifically the last value in your file.
The way you allocate memory is also not really ok, same goes for the way you open your file, there is memory leaking etc. I am not going into details.
At least this issue:
Copy the string
OP's goal includes the need to copy the string from the read buffer to the list, not just copy the buffer pointer.
// void addTolist(number_list_t* list, void* newNumber) {
void addStringTolist(number_list_t* list, const char *s) {
// number_node_t* newNode = calloc(1,sizeof(number_node_t));
number_node_t* newNode = calloc(1, sizeof *newNode); // todo: add error check
size_t sz = strlen(s) + 1;
newNode->number = malloc(sz); // todo: add error check
strpy(newNode->number, s);
newNode->next = list->head;
list->head = newNode;
}
Note: When freeing the list, newNode->number also needs to be free'd.
regarding:
while(fgets(secondStr,MAX,missileFile) != NULL)
MAX is defined as 10000 but secondStr is defined as pointer to one byte. so when this is executed, a buffer overflow occurs.
This is undefined behavior and probably the root of the problem with reading from a file
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
My assignment asks us to shorten the words of an user input sentence. Then put the shortened words into a linked list. When the gears of code get stuck: the last word in the sentence gets saved into every node. What repair should be implemented so the code puts a diff word into a node each time.
note: I looked at questions involving memcpy & implemented using 0 and\0 to fill the arrays beforehand. I've also changed the arguments of memcpy with & and without&. I also used memmove and strncpy. This Variation of 'memcpy in for loop to copy substring of array into node' has not been asked.
Here is my code. Would appreciate recommendations for learning resources links to c or java in the comments of your answer. As well as suggestions for improving code. Of course if you have a more concise/accurate version of my question I will gladly update it. Thank you!
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
typedef struct node
{
char *four_letters;
struct node *next_node;
}node;
struct node* head= NULL;
char sentence[120][40]={0}, four_letters[40]={0}; // Tried \0,"0".
int word, num_words=-1;
void scan(); void print(); void sentence_into_list();
void add(struct node **head, char *four_letters);
void display(struct node *head);
int main()
{
scan();
printf("\n");
print();
printf("\n");
sentence_into_list();
display(head);
return 0;
}
void scan()
{
for(word=0;;word++)
{
scanf("%s",sentence[word]);
num_words++;
if(getchar()=='\n')
break;
}
}
void print()
{
for(word=0;word<=num_words;word++)
{
printf("%s ", sentence[word]);
}
}
void sentence_into_list()
{
for (word=0;word<=num_words;word++)
{
memcpy(four_letters, sentence[word], 4); //tried & //tried strncpy, memmove.
add(&head, four_letters);
}
}
void add(struct node **head, char *four_letters)
{
struct node *new_node = malloc(sizeof(struct node));
new_node->four_letters = four_letters;
new_node->next_node = *head;
*head=new_node;
}
void display(struct node* head)
{
struct node *current;
current = head;
if(current!=NULL)
{
printf("List:");
do
{
printf("%s ",current->four_letters);
current = current->next_node;
}
while(current!=NULL);
printf("\n");
}
else
{
printf("empty\n");
}
}
the last word in the sentence gets saved into every node. ....
This is happening because four_letters pointer of all the nodes of the list are pointing to the same memory location four_letters [char buffer declared globally - four_letters[40]={0};]. Hence, whatever is the last value of four_letters will be reflected in all nodes.
One way of solving this problem is -
allocate a memory, large enough to hold the data, to the node four_letters pointer and copy the content of four_letters to it. Alternatively, you can use strdup which does this for you.
So, in the add() function, replace this
new_node->four_letters = four_letters;
with this
new_node->four_letters = strdup(four_letters);
strdup creates a duplicate of the string passed to it. It returns a pointer to newly allocated memory so, you should free it once you are done with it, like this:
free (node_ptr->four_letters); //node_ptr is pointer to current node
While freeing the dynamically allocated memory of list nodes, make sure to first free the dynamically allocated members of the node structure and then free the node itself.
The other way of solving this problem is -
Instead of having a pointer to the char in node structure, have the char array as the member of node structure, like this:
typedef struct node
{
char four_letters[5]; // 5 because it is suppose to keep the four letters only and +1 is for null-terminating character
struct node *next_node;
}node;
and copy the content of four_letters passed to add() to the structure node member four_letters. With this, you don't need to take care of freeing the memory.
There is one more problem with your code -
In the function sentence_into_list(), you are doing:
memcpy(four_letters, sentence[word], 4);
add(&head, four_letters);
Here you're copying the first 4 characters of sentence[word] to four_letters but you should also add the null-terminating character at the 5th location of the buffer four_letters before passing it to add(), something like this:
four_letters[4] = '\0';
C language does not have the native string type. In C, strings are actually a one-dimensional array of characters terminated by a null character \0.
You are not seeing any problem in your code because you are initializing the buffer with zeros:
four_letters[40]={0};
and every time you are only copying only the 4 characters to it. So, at the 5th location you always have \0. But assume a case where you are using the buffer for different size of strings. In such case, you must have to place the terminating null-character at the end of the string.
Additional:
I can see that you are nowhere freeing the memory allocated dynamically for the nodes of the list. Follow the good programming practice, make a habit of freeing the dynamically allocated memory once you are done with it.
I am trying to copy strings from a field in one struct to another struct (a node), so that I can ultimately create a hashtable. However, I seem to be having some issues in the actual string copying. I've created a for loop to iterate over the strings in the source stuct, and I know the iteration is working fine, because if I printf the source strings (data[i].c_name), they print out fine. Unfortunately, when I try to printf the destination (class_id), it seems to be empty (and thus of course my hash function isn't doing much). Any insights into the potential problem here would be greatly appreciated. Please let me know if I haven't given enough context.
#define LENGTH 30
#define MAX_OBS 80000
typedef struct
{
char c_name[LENGTH];
char s_name[LENGTH];
double value[MAX_OBS];
}
sample;
typedef struct node
{
char class_id[LENGTH];
struct node *next;
}
node;
{
char class_id[LENGTH];
for (int i = 0; i < total_columns; i++)
{
// malloc a new node pointer for each new class label
node *new_node = malloc(sizeof(node));
// check that there was sufficient memory
if (new_node == NULL)
{
return 6;
}
// copy c_name into node -- failing - class_id is empty
strcpy(new_node->class_id, data[i].c_name);
printf("%s\n", class_id);
}
}
Drop the last char class_id[LENGTH]; that you print as it was never initialized. Then switch your printf() to use the actual target of the strcpy.
strncpy(new_node->class_id, data[i].c_name, LENGTH);
printf("%.*s\n", LENGTH, new_node->class_id);
I've also put a few LENGTH limits in my code to assure you don't do bad things on bad input without a terminal \0. Never blindly trust your C input unless you generated it in a fail-safe manner.
Disclaimer: desktop inspection changes. Actual debugging is left as an exercise to the student.
So I'm doing some linked list revison and Im trying to just load a list with some numbers and then print it out. Below is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct stack {
int data;
struct stack *next;
}*stack;
stack create_s(void){
stack s = (void*)malloc(sizeof(stack));
s->next = NULL;
return s;
}
void push_s(stack s, int data) {
while (s->next != NULL) {
s = s->next;
}
s->next = (void*)malloc(sizeof(stack));
s=s->next;
s->data = data;
s->next = NULL;
}
void print_s(stack s) {
if (s==NULL) {
return;
}
else {
while (s->next != NULL) {
printf("%d\n",s->data);
s=s->next;
}
}
}
int main (void) {
stack s = create_s();
push_s(s,2);
push_s(s,4);
push_s(s,6);
push_s(s,8);
print_s(s);
return 0;
}
My output is however:
-1853045587
2
4
6
when it should be
2
4
6
8
Is it printing the address of my struct at the beginning? Also, why is it not printing my last element?
Thanks
The code contains several errors, but the first thing that catches the eye is that your memory allocation is already obviously broken
stack s = (void*)malloc(sizeof(stack));
You defined stack as a pointer type. This means that sizeof(stack) evaluates to pointer size and the above malloc allocates enough space to store a single pointer, not enough for the entire struct stack object. The same memory allocation error is present in push_s as well.
Here's some advice
Don't hide pointer types behind typedef names. Define your stack as
typedef struct stack{
int data;
struct stack *next;
} stack;
and use stack * wherever you need a pointer. I.e. make that * visible instead of hiding it "inside" a typedef name. This will make your code easier to read.
Don't cast the result of malloc. Anyway, what is the point of casting it to void * when it is void * already???
Don't use sizeof with types unless you really really have to. Prefer to use sizeof with expressions. Learn to use the following malloc idiom
T *p = malloc(sizeof *p);
or, in your case
struct stack *s = malloc(sizeof *s);
This will allocate a memory block of appropriate size.
Also, as #WhozCraig noted in the comments, the very first node in your list is apparently supposed to serve as a "sentinel" head node (with undefined data value). In your code you never initialize the data value in that head node. Yet in your print_s function you attempt to print data value from the head node. No wonder you get garbage (-1853045587) as the first line in your output. Don't print the very first node. Skip it, if it really is supposed to serve as a sentinel.
Also, the cycle termination condition in print_s looks strange
while (s->next != NULL)
Why are you checking s->next for NULL instead of checking s itself? This condition will terminate the cycle prematurely, without attempting to print the very last node in the list. This is the reason why you don't see the last element (8) in your output.
The actual cause of the given output can be fixed by changing:
s=s->next;
s->data = data;
to
s->data = data;
s=s->next;