I'm pretty new to C and pointers.
Following codes are for implementing a linked list in which each node contains a data of record.
However, when I compile and run this program, it shows an error "segmentation fault", and I guess the following part from my code makes an error.
head->next = NULL in functions in list.c
I doubt the segmentation fault error happens due to dereferencing a null pointer but have no idea what's wrong with my code.
list.h
#ifndef LIST_H
#define LIST_H
#include <stddef.h>
#include "record.h"
typedef struct node node;
struct node {
record data;
node *next;
};
typedef node *record_list; /* a record list is represented by its "head"
pointer */
void list_init(record_list *plist);
int list_insert(record_list *plist, const record *prec);
void list_clear(record_list *plist);
void list_print(const record_list *plist);
#endif
io.h
#ifndef IO_H
#define IO_H
#include "record.h"
void print_record(const record *p);
int read_record(record *p);
/* reads a string from stdin */
int get_word(const char prompt[], char word[]);
/* reads an int from stdin */
int get_int(const char prompt[], int *p);
#endif
record.h
#ifndef RECORD_H
#define RECORD_H
#define IDSIZE 10
#define NAMESIZE 20
typedef struct {
char last[NAMESIZE];
char first[NAMESIZE];
} name;
typedef struct {
char id[IDSIZE];
name name;
int score;
} record;
#endif
list.c
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "record.h"
#include "list.h"
#include "io.h"
/* initializes a record list (specified via plist) to an empty list */
void list_init(record_list *plist) {
node *head;
head = *plist;
head = NULL;
head->next = NULL;
printf("%s", "segmentation???\n");
}
/*
* inserts a record (specified via prec) into a record list
*/
int list_insert(record_list *plist, const record *prec) {
node *current, *temp;
printf("%s", "list insert\n");
current = *plist;
while (current->next != NULL) {
current = current->next;
}
temp = (node *)malloc(sizeof(node));
if (temp == NULL) {
fprintf(stderr, "memory allocate failed");
return 0;
}
current->next = temp;
current->next->data = *prec;
current->next->next = NULL;
printf("%s", "list insert done\n");
return 1;
}
/*
* deallocates all dynamic memory associated with a record list (specified
* via plist) & resets the record list to an empty list
*/
void list_clear(record_list *plist) {
printf("%s", "list clear\n");
free((*plist)->next);
plist = NULL;
(*plist)->next = NULL;
}
/* prints all records in a record list (specified via plist) */
void list_print(const record_list *plist) {
node *current;
current = *plist;
printf("%s", "list print\n");
while (current->next != NULL) {
print_record(&(current->data));
current = current->next;
}
}
io.c
#include <stdio.h>
#include <string.h>
#include "record.h"
#include "io.h"
#define LINESIZE 1024
/*
* prints a record (specified via p);
*/
void print_record(const record *p) {
printf("%d %s %s %s\n", p->score, p->name.last, p->name.first, p->id);
}
/*
* reads a record from stadard input & stores it via p;
*/
int read_record(record *p) {
return (
get_word("Enter id: ", p->id)
&& get_word("Enter last name: ", p->name.last)
&& get_word("Enter first name: ", p->name.first)
&& get_int("Enter score: ", &(p->score))
);
}
/* reads a string from stdin */
int get_word(const char prompt[], char word[]){
char line[LINESIZE];
char temp[LINESIZE];
while (1) {
printf("%s", prompt);
if(!fgets(line, LINESIZE, stdin)){
clearerr(stdin);
return 0;
}
if (sscanf(line, "%s", temp) == 1){
strcpy(word, temp);
return 1;
}
}
}
/* reads an int from stdin */
int get_int(const char prompt[], int *p) {
char line[LINESIZE];
while (1) {
printf("%s", prompt);
if (!fgets(line, LINESIZE, stdin)) {
clearerr(stdin);
return 0;
}
if (sscanf(line, "%d", p) == 1) {
return 1;
} else {
printf("%s", "Error: The input is not given in integer.\n");
}
}
}
main.c
#include <stdio.h>
#include "record.h"
#include "list.h"
#include "io.h"
int main(void) {
record_list list;
record r;
printf("address of list: %ld\n", &list);
printf("address of list: %ld\n", &(list->next));
list_init(&list);
while (read_record(&r)) {
printf("%s\n", "read success");
if (!list_insert(&list, &r))
break;
}
list_print(&list);
return 0;
}
If your goal is to create an empty list and plist is the pointer to the head of the list you have to set the variable pointed by plist to NULL with *plist = NULL; , you can get rid of the code is causing the segmentation fault
Ok I think I find the next error:
current = *plist;
while (current->next != NULL) {
current = current->next;
}
Will cause errors because the first time you call list_insert you have *plist equals to NULL because the list is empty and so current->next != NULL will cause the error (current is also equals to NULL)
I suggest the following:
printf("%s", "list insert\n");
if (*plist == NULL) {
temp = (node * )malloc(sizeof(node));
if (temp == NULL) {
fprintf(stderr, "memory allocate failed");
return 0;
}
plist = temp;
(*plist) ->data = *prec;
(*plist) ->next = NULL;
return 1;
}
current = *plist;
while (current->next != NULL) {
current = current->next;
}
And the rest of the code as it was, I added an if for the case *pilist is equals to NULL, in that case temp is going to point at the first element and has to be assigned to plist
Related
My teacher gave me a library that describes a single linked list. I am writing a main file to test it, and i ran into a very weird problem.
This is the header for the linked list library (There are more function, but i only putin the one i used):
#ifndef DSSINGLYLINKEDLIST_H
#define DSSINGLYLINKEDLIST_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _SListEntry SListEntry;
typedef struct _SListIterator SListIterator;
typedef void *SListValue;
/**
* Definition of a #ref SListIterator.
*/
struct _SListIterator {
SListEntry **prevNext;
SListEntry *current;
};
#define SLIST_NULL ((void *) 0)
typedef int (*SListCompareFunc)(SListValue value1, SListValue value2);
typedef int (*SListEqualFunc)(SListValue value1, SListValue value2);
SListEntry *slist_append(SListEntry **list, SListValue data);
SListValue slist_nthData(SListEntry *list, unsigned int n);
unsigned int slist_length(SListEntry *list);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef DSSINGLYLINKEDLIST_H */
This is my .c file:
#include <stdlib.h>
#include <stdio.h>
#include "dssinglylinkedlist.h"
struct _SListEntry {
SListValue data;
SListEntry *next;
};
SListEntry *slist_append(SListEntry **list, SListValue data)
{
/* Create new list entry */
SListEntry *newEntry = malloc(sizeof(SListEntry));
if (newEntry == NULL) {
return NULL;
}
newEntry->data = data;
newEntry->next = NULL;
/* Hooking into the list is different if the list is empty */
SListEntry *rover;
if (*list == NULL) {
/* Create the start of the list */
*list = newEntry;
} else {
/* Find the end of list */
rover=*list;
while (rover->next != NULL) {
rover = rover->next;
}
/* Add to the end of list */
rover->next = newEntry;
}
return newEntry;
}
SListValue slist_nthData(SListEntry *list, unsigned int n)
{
/* Find the specified entry */
SListEntry *entry = slist_nthEntry(list, n);
/* If out of range, return NULL, otherwise return the data */
if (entry == NULL) {
return SLIST_NULL;
} else {
return entry->data;
}
}
unsigned int slist_length(SListEntry *list)
{
SListEntry *entry = list;
unsigned int length = 0;
while (entry != NULL) {
/* Count the number of entries */
++length;
entry = entry->next;
}
return length;
}
I think there's nothing wrong with these code.
I am writing a main using this library to store information of two polynomial:
#include <stdio.h>
#include <stdlib.h>
#include "dssinglylinkedlist.h"
void printPolynomial(SListEntry*);
int main()
{
SListEntry *poly1;
int n;
printf("Input n for poly1: ");
scanf("%d", &n);
printf("Input poly1: ");
for (int i=0; i<=n; i++) {
int *temp = (int *) malloc(sizeof (int));
scanf("%d", temp);
slist_append(&poly1, temp);
}
printPolynomial(poly1);
SListEntry *poly2;
printf("Input n for poly2: ");
scanf("%d", &n);
printf("Input poly2: ");
// for (int i=0; i<=n; i++) {
// int *temp = (int *) malloc(sizeof (int));
// scanf("%d", temp);
// slist_append(&poly2, temp);
// }
// printPolynomial(poly2);
return 0;
}
void printPolynomial(SListEntry *list)
{
int length = (int)slist_length(list);
for (int i = 0; i < length; i++) {
int temp = *((int *)slist_nthData(list,(unsigned int)i));
if (i >0 && temp >= 0) {
printf("+");
}
printf("%d*x^%d", temp, length-i-1);
}
printf("\n");
}
So if i comments the second loop (after i print 'Input poly2', like i wrote above), i can still input my poly1 and print it. But if i un-comments it, my program crashes immediately when i append the first element of poly1.
What is the problem of my code?
I am creating a program that will read a word from a text file in main.c, and send it over to list.c file to create a new node to store that word. The node will also store three ints: first (number of times this word appears in txt file 1), second(number of times this word appears in txt file 2), and dif (abs(first-second)). After adding all the new words to the file and counting the number of times each word exists in each txt file, the main.c will call a method that will calculate the difference between first and second for each node. This is difference (stored in dif for each node) will be used to sort the linked nodes in decreasing order.
EX. word: the, first: 2888, second: 2466, dif: 422.
red, 39 12 27
.....
However, when main calls the sort method, a infinite loop occurs. This infinite loop comes from the inner loop of the sorting algorithm, where the current node is assigned the node from the curr->next pointer. Somewhere during the sort method, the current node's next pointer points to the current node, not the actual next node in the linkedlist. If the sort method is dactivated, then all other functions work fine, including printAll which goes through the entire list and prints the data in each node (see my example above).
My issue is that I cannot find where in my sort method how current->next started to point to the current node. Any help is appreciated!
/*
* list.h
*/
#ifndef LIST_H_
#define LIST_H_
typedef struct node Node;
void findWord(char *word, int book);
void addWord(char *word, int book);
void editWord(Node **endPtr, int book);
void sort();
void swap(Node **a, Node **b);
void calculateDiff();
void printAll();
#endif /* LIST_H_ */
/*
* list.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
typedef struct node{
int first;
int second;
int dif;
char name[20];
struct node *next;
}Node;
Node *front = NULL;
/*
* Sees if the current word exists in the
* linkedlist.
*/
void findWord(char *word, int book) {
Node *curr = front;
int boolean = 0;
while (curr != NULL) {
if(strcmp(curr->name, word) == 0) {
boolean = 1;
editWord(&curr, book);
break;
}
curr = curr->next;
}
if(!boolean) { //Add word if it does not exist.
addWord(word, book);
}
}
/*
* Creates a new node for the added word. Adds to front.
*/
void addWord(char *word, int book) {
Node *newNode = malloc (sizeof(Node));
/*
* Since this word is being added
* to the linkedlist with a newly
* created node, either the
* first or second int must be to 1
* while the other is set to 0. Based
* off of book int.
*/
if(book == 1) {
newNode->first = 1;
newNode->second = 0;
} else {
newNode->first = 0;
newNode->second = 1;
}
newNode->dif = 0;
strcpy(newNode->name, word);
newNode->next = front;
front = newNode;
}
/*
* Edits the data for an existing word.
* Only called if current word exists in
* the linkedlist.
*/
void editWord(Node **endPtr, int book) {
if (book == 1) {
(*endPtr)->first++;
} else {
(*endPtr)->second++;
}
}
/*
* Sorts the list in descending order based on
* difference value.
*/
void sort() {
Node *curr, *last = NULL;
curr = front;
while (curr != last) {
while (curr->next != last) {
if(curr->dif < curr->next->dif ) {
swap(&curr, &curr->next);
}
curr = curr->next;
}
last = curr;
curr = front;
}
}
/*
* Swaps the data in the current and next node in the list.
*/
void swap(Node **a, Node **b) {
int temp;
char nameTemp[20];
//Swap first
temp = (*a)->first;
(*a)->first = (*b)->first;
(*b)->first = temp;
//Swap second
temp = (*a)->second;
(*a)->second = (*b)->second;
(*b)->second = temp;
//Swap dif
temp = (*a)->dif;
(*a)->dif = (*b)->dif;
(*b)->dif = temp;
//Swap name
strcpy(nameTemp, (*a)->name);
strcpy((*a)->name, (*b)->name);
strcpy((*b)->name, nameTemp);
}
/*
* Calculates the difference between first and second
*/
void calculateDiff() {
Node *curr = front;
while(curr != NULL) {
curr->dif = abs((curr->first - curr->second));
curr = curr->next;
}
}
/*
* Prints all the data from the nodes.
*/
void printAll() {
printf("|| Word || RedBadge || LittleRegiment || Diff\n");
Node *curr = front;
while ( curr != NULL ) {
printf("%s, %d, %d, %d\n", curr->name, curr->first, curr->second, curr->dif);
curr = curr->next;
}
}
/*
* main.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "list.h"
void readBook(int book, FILE *infile);
void readLine(char *line, int book);
int main (void) {
setvbuf(stdout, NULL, _IONBF,0);
FILE *infile = fopen("RedBadge.txt", "r");
FILE *infile2 = fopen("LittleRegiment.txt", "r");
readBook(1, infile);
readBook(2, infile2);
fclose(infile);
fclose(infile2);
calculateDiff();
sort();
printAll();
return 0;
}
void readBook(int book, FILE *infile) {
char line[70];
//Read in each line
while (!feof(infile)) {
fgets(line, 70, infile);
readLine(line, book);
}
}
void readLine(char *line, int book) {
int i = 0, j = 0;
char word[20];
while (line[i]) {
line[i] = tolower(line[i]); //Convert line to lowercase
if((line[i] <= 'z' && line[i] >= 'a') || line[i] == 39 || line[i] == '-') {
word[j] = line[i];
j++;
} else if (j != 0) {
word[j] = '\0';
findWord(word, book);
j = 0;
}
i++;
}
}
I believe your error is actually a buffer overflow. There are words in those books that are longer than 19 characters (the max that will fit in your word variable). When your readline function tries to read those words it will write outside the boundaries of the word array, which is undefined behavior. It will then also use strcpy to copy the word into the node, which will also overflow the node's word array.
A quick fix is to just throw away the extra characters past 19 that won't fit in your word array. In readline add a test for how big j is:
if (j < sizeof word - 1) {
word[j] = line[i];
j++;
}
One of the words in question is "ain't--plundering----" (at least in the copy of the text i downloaded), which leads me to think maybe you also should split words on punctuation.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_LENGHT 30
typedef struct numnode
{
char* dataPtr;
struct numnode* next;
} NUMNODE;
typedef struct num
{
NUMNODE* head;
} NUM;
//////
//////
//////
int main()
{
char *wp;
char word[80];
int total=0;
FILE *test= fopen("book.txt", "r");
while (fscanf (test, "%s",word) == 1)
{
//printf("%s\n",word); //counting how many words in a book.txt
total++;
}
if (total==0)
{
printf("File not found\n"); //if no word, then return
return;
}
NUM* dic;
dic=(NUM*)malloc(sizeof(NUM)*total);
NUMNODE* temp;
temp=dic->head;
FILE*file = fopen("book.txt", "r");
while(!feof(file))
{
wp=malloc(100);
printf("test1\n");
fscanf(file,"%s",wp);
strcpy(temp->dataPtr,wp); //strcpy is the error part
printf("test2\n");
temp=temp->next;
}
return;
}
this c code read word by word from book.txt and put them to linked
list. i got some issues with !feof(file) part.Couldnt figure out what
to do.i think strcpy in this loop is the reason of this issue.im
waiting for your helps :3
Error is because the struct member dataPtr is a pointer, not an array. So the strcpy call
strcpy(temp->dataPtr,wp);
is wrong because it accesses illegal memory invoking undefined behaviour. What you need is
typedef struct numnode
{
char dataPtr[100]; // dataPtr changed to an array type
struct numnode* next;
} NUMNODE;
Please note that dataPtr must be at least the size of the buffer pointed to by wp.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_LENGHT 30
typedef struct numnode {
char* dataPtr;
struct numnode* next;
} NUMNODE;
typedef struct num {
NUMNODE* head;
} NUM;
int main(){
NUM dic = { NULL };
char word[WORD_LENGHT];
int total=0;//num of word
FILE *file= fopen("book.txt", "r");
NUMNODE *curr = NULL, *temp;
while (fscanf(file, "%29s", word) == 1) {
temp = malloc(sizeof(*temp));
temp->dataPtr = malloc(strlen(word) + 1);
temp->next = NULL;,
strcpy(temp->dataPtr, word);
if(curr){
curr = curr->next = temp;
} else {
dic.head = curr = temp;
}
++total;
}
if (total==0){
printf("File does not has word\n");
return;
}
//test print
printf("%d\n", total);
if(total>1){
printf("%s\n", dic.head->dataPtr);
printf("%s\n", dic.head->next->dataPtr);
}
//do something
return;
}
,
I'm trying to upload a list from a outside FILE into a linked list and have all the chars from the FILE be accessible on the list. I have this so far, but It only contains the last word from my input file list. I don't know what the problem is and I'm not sure where to go from here. Any help would be great! Thank you.
My .txt file that I'm uploading is just a bunch of nonsense words like:
Ted
Greg
Shoe
Money
Apple
When I run the program the list would only contain the would Apple.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 15
#define INPUT 1
#define OUTPUT 2
struct tree_node{
char string[MAXLEN+1];
struct tree_node *left_child, *right_child;
}*first = NULL;
int main(int argc, char *argv[])
{
char cell[MAXLEN];
int op;
FILE *pf;
FILE *out;
pf = fopen(("%s", argv[INPUT]), "r");
if(pf == NULL){
fprintf(stderr, "Error: File is Empty. \n");
return 0;
}else{
struct tree_node *temp;
struct tree_node *nn=(struct tree_node*)malloc(sizeof(struct tree_node));
while(!feof(pf)){
// fgets(&nn->string, MAXLEN, pf);
fscanf(pf, "%s", &nn->string); //I think this is where the problem is.
if(first != NULL){
temp = first;
while(temp -> right_child != NULL)
temp = temp -> right_child;
temp -> right_child = nn;
}else{
first = nn;
}
nn->right_child = NULL;
}
}
do{
printf("1.Display.\n2.Exit.\n");
printf("Selection?\n");
scanf("%d", &op);
switch(op)
{
case 1:display();
break;
}
}
while(op < 2 && op > 0);
}
int display()
{
struct tree_node *temp;
temp = first;
if(temp == NULL)
{
printf("EMPTY!\n");
return;
}
printf("Elements: \n");
while(temp != NULL){
printf("%s\n", temp -> string);
temp = temp -> right_child;
}
}
fscanf(pf, "%s", &nn->string); Here string is char array. so remove&.
You created only one node. This section above while().
struct tree_node *temp;
struct tree_node *nn=(struct tree_node*)malloc(sizeof(struct tree_node));
Need to create separate node for each string.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 15
#define INPUT 1
#define OUTPUT 2
#define EXIT 2
#define _S(x) #x
#define S(x) _S(x)
struct tree_node{
char string[MAXLEN+1];
struct tree_node *left_child, *right_child;
}*first = NULL;
void display(void);
void add_tree(char string[MAXLEN+1]);
int main(int argc, char *argv[]){
char cell[MAXLEN+1];
int op;
FILE *pf, *out;
if(NULL==(pf = fopen(argv[INPUT], "r"))){
fprintf(stderr, "Error: File can't open.\n");
return 1;
}
while(fscanf(pf, " %" S(MAXLEN) "[^\n]", cell)==1){
add_tree(cell);
}
fclose(pf);
do{
printf("1.Display.\n2.Exit.\n");
printf("Selection?\n");
scanf("%d", &op);
switch(op){
case 1:
display();
break;
}
} while(op != EXIT);
//release tree
return 0;
}
struct tree_node* new_node(char string[MAXLEN+1]){
struct tree_node *np = malloc(sizeof(*np));
if(np){
strcpy(np->string, string);
np->left_child = np->right_child = NULL;
}
return np;
}
void insert(struct tree_node **np, char string[MAXLEN+1]){
int cmp;
if(*np == NULL){
*np = new_node(string);
return;
}
if(0==(cmp=strcmp((*np)->string, string)))
return;
if(cmp > 0)
insert(&(*np)->left_child, string);
else
insert(&(*np)->right_child, string);
}
void add_tree(char string[MAXLEN+1]){
insert(&first, string);
}
void display_r(struct tree_node *np){
if(np){
display_r(np->left_child);
printf("%s\n", np->string);
display_r(np->right_child);
}
}
void display(void){
if(first == NULL){
printf("EMPTY!\n");
return;
}
printf("Elements: \n");
display_r(first);
}
#include <stdio.h>
#include <stdlib.h>
/* Report an error and abort */
#define FATAL_ERROR(message) \
{ \
fprintf(stderr,"In %s(%d) [function %s]: %s\n", \
__FILE__, __LINE__, __FUNCTION__ , (message) ); \
abort(); \
} \
/* Report a posix error (similar to perror) and abort */
#define FATAL_PERROR(errcode) FATAL_ERROR(strerror(errcode))
void* Malloc(size_t n)
{
void* new = malloc(n);
if(new==NULL) FATAL_ERROR("Out of memory.");
return new;
}
typedef struct twit{
char data[141]; //contains the actual data
//struct twit *prev; //pointer to previous node (Closer to front)
struct twit *next; //pointer to next node (Closer to back)
}twit;
typedef struct twitbuffer{
twit *first;
twit *last;
int size;
}twit_buffer;
/*
function for create a new buffer
*/
void new_twitbuffer(twit_buffer *a)
{
a=Malloc(sizeof(twit)*12000);
a->first = a->last = NULL;
a->size = 0;
return;
}
int twitbuffer_empty(twit_buffer *a) {
if(a->first == NULL)
return 1;
else
return 0;
}
/*
function to insert a new twit in the buffer
*/
void insertTwit(twit_buffer *a, char *data)
{
twit new;
if (strlen(&data)<=140){
strcpy(&new.data,data);
}
else{
printf("Twit > 140 characters...");
}
if (new.data == NULL) {
//errno = ENOMEM;
printf("error!");
return;
}
if(a->first==NULL){
a->first = a->last = &new;
}else{
a->last->next=&new;
a->last=&new;
}
new.next= NULL;
a->size++;
return;
}
char* popTwit(twit_buffer *a) {
if (twitbuffer_empty(a)) {
return NULL;
}
char *data;
//strcpy(&data,a->first->data);
data=a->first->data;
if (a->first == a->last)
a->first = a->last = NULL;
else
a->first = a->first->next;
a->size--;
return data;
}
twit_buffer mytwitbuffer;
int main()
{
new_twitbuffer(&mytwitbuffer);
//printf("a=%d",mytwitbuffer);
char *a = "first twit\n";
char *b = "second twit\n";
char *c = "third twit\n";
insertTwit(&mytwitbuffer, a);
insertTwit(&mytwitbuffer, b);
insertTwit(&mytwitbuffer, c);
char *poppp;
poppp = popTwit(&mytwitbuffer);
printf("%s", poppp);
poppp = popTwit(&mytwitbuffer);
printf("%s", poppp);
poppp = popTwit(&mytwitbuffer);
printf("%s", poppp);
}
This is my code for an implementation of a queue. When i execute this i take this result:
thir�it
(null)(null)
This means that the two first insertions are not being done correctly and the third goes in stdout in a "paranormal" way! Do you have any ideas?
You are storing a reference to the local variable 'new' in your twit buffer. You should Malloc it, instead Of declaring It local