Problems regarding an multiple choice question program - c

I have created a program to generate the result of a multiple choice exam. The program was supposed to show the total number of mistakes, blank answers and the number of the question which were answered incorrectly. For the following input:
6
1..223
(Here . means blank answer)
123124
The output was supposed to be:
Your result:
Mistakes: 3
Blanks: 2
Your mistakes are following:
4 5 6
Your blanks are following:
2 3
But the code shows undefined behavior. It seems to go through infinite loop. Expecting solution to my problem shortly. Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char data;
struct node* next;
}node;
void printNode(node* head)
{
node* local = head;
int i = 0;
if(local -> data == 0)
{
printf("0");
return;
}
while(local != NULL)
{
if(i == 3)
{
i = 0;
printf("\n");
}
printf("%d\t", local -> data);
local = local -> next;
++i;
}
}
void freeNode(node** head)
{
node* temp = (*head);
while((*head) != NULL)
{
(*head) = (*head) -> next;
free(temp);
temp = (*head);
}
}
int main()
{
int n, i, flagB, flagM, blnk, mstk;
blnk = mstk = flagB = flagM = 0;
printf("Enter the number of questions: ");
scanf("%d", &n);
char ques[n], ans[n];
if(n == 0)
return 0;
node* headM = (node*)malloc(sizeof(node));
node* nodeM;
node* headB = (node*)malloc(sizeof(node));
node* nodeB;
printf("Enter your given answers: ");
fflush(stdin);
for(i = 0; i < n; ++i)
{
scanf("%c", &ques[i]);
}
fflush(stdin);
ques[n] = '\0';
printf("Enter the solution: ");
for(i = 0; i < n; ++i)
{
scanf("%c", &ans[i]);
}
ans[n] = '\0';
for(i = 0; i < n; ++i)
{
if(ques[i] == '.')
{
++blnk;
if(flagB == 0)
{
headB -> data = i + 1;
headB -> next = NULL;
nodeB = headB;
continue;
}
nodeB -> next = (node*)malloc(sizeof(node));
nodeB = nodeB -> next;
nodeB -> data = i + 1;
nodeB-> next = NULL;
flagB = 1;
}
else if(ques[i] != ans[i])
{
++mstk;
if(flagM == 0)
{
headM -> data = i + 1;
headM -> next = NULL;
nodeM = headM;
continue;
}
nodeM -> next = (node*)malloc(sizeof(node));
nodeM = nodeM -> next;
nodeM -> data = i;
nodeM-> next = NULL;
flagM = 1;
}
}
printf("Your result:\n\tMistakes: %d\n\tBlanks: %d\n", mstk, blnk);
printf("Your mistakes are follwing:\n");
printNode(headM);
printf("\nYour blanks are follwing:\n");
printNode(headB);
freeNode(&headM);
freeNode(&headM);
return 0;
}

Here are some additional thoughts. What makes your code very convoluted and hard to debug and keep the logic straight is you are mixing your linked-list Add function within the logic of your blanks and mistakes and using special conditions to handle adding the first node and subsequent nodes. This make things difficult to test and debug. If you need to add nodes to a linked-list, then write an add() function that you can thoroughly test and debug before putting it to use in your code.
Your VLAs ques and ans are too short to hold a string of n characters, at minimum they must be n + 1 characters long to provide storage for the nul-termining character that marks the end of the string. Ideally, you will make them at least 2-character longer to also hold the '\n' which will allow you to take input with fgets() rather than looping scanf() a character at a time -- which is just nuts.
You do not need to pass the address of the pointer to freeNode() simply pass a pointer. Sure freeNode() will receive a copy of the pointer -- but it will contain the original address -- and since you don't have to make any changes to that pointer available back to the caller, there is no need to pass the address of the pointer (there won't be any list left to worry about when you are done...)
So putting those pieces together, adding an add() function to add to your linked lists (See Linus on Understanding Pointers for why a pointer-to-pointer is used to iterate to the end), and adding a simple empty_stdin() function to remove the '\n' left in stdin from reading n with scanf() before making calls to fgets() later for ques and ans, you could do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* simple function to empty stdin to end-of-line */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
typedef struct node
{
int data;
struct node *next;
} node;
node *add(node **head, int v)
{
node **ppn = head, /* pointer to pointer to head */
*pn = *head, /* pointer to head */
*newn = malloc (sizeof *newn); /* allocate new node */
if (!newn) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
newn->data = v; /* initialize members values */
newn->next = NULL;
while (pn) { /* iterate to end of list */
ppn = &pn->next;
pn = pn->next;
}
return *ppn = newn; /* add & return new node */
}
void printNode (node *head)
{
for (; head; head = head->next)
printf (" %d", head->data);
putchar ('\n');
}
void freeNode(node *head)
{
while (head != NULL)
{
node *victim = head;
head = head->next;
free(victim);
}
}
int main()
{
int n, i, blnk, mstk;
blnk = mstk = 0;
node *headM = NULL; /* declare pointers and initialize NULL */
node *headB = NULL;
printf ("Enter the number of questions: ");
/* you must VALIDATE every user-input */
if (scanf ("%d", &n) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
empty_stdin(); /* remove '\n' (and any other chars from user) */
/* before calling fgets() below */
if (n == 0) /* check 0 BEFORE VLA declaration */
return 0;
char ques[2*n], ans[2*n]; /* declare question/answer VLAs, don't skimp */
printf("Enter your given answers: ");
if (!fgets(ques, sizeof ques, stdin)) /* read ques from stdin */
return 1;
ques[strcspn(ques, "\r\n")] = 0; /* trim '\n' from end of ques */
printf("Enter the solution: ");
if (!fgets(ans, sizeof ans, stdin)) /* read ans from stdin */
return 1;
ans[strcspn(ans, "\r\n")] = 0; /* ditto for ans */
for(i = 0; i < n; ++i) /* loop n times */
{
if(ques[i] == '.') /* if blank */
{
add (&headB, i + 1); /* add to list headB */
++blnk; /* increment counter */
}
else if(ques[i] != ans[i]) /* if mistake */
{
add (&headM, i + 1); /* add to list headM */
++mstk; /* increment counter */
}
}
printf ("Your result:\n\tMistakes: %d\n\tBlanks: %d\n"
"Your mistakes are following:\n", mstk, blnk);
printNode(headM);
printf("\nYour blanks are following:\n");
printNode(headB);
freeNode(headM); /* no need to pass the address of the pointer to free */
freeNode(headB); /* there won't be a list left when freeNode is done */
return 0;
}
There is a lot there, so go through it slowly.
Example Use/Output
$ ./bin/llquestions
Enter the number of questions: 6
Enter your given answers: 1..223
Enter the solution: 123124
Your result:
Mistakes: 2
Blanks: 2
Your mistakes are following:
4 6
Your blanks are following:
2 3
(note: in 1..223 and 123124, 5 is not a mistake, the 2 is in the correct position at the end)
Look things over and let me know if you have further questions.

I made some changes to this code, check this out.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node node;
struct Node
{
int data;
struct Node * next;
};
void printNode(node *head)
{
node *local = head;
while (local != NULL)
{
printf("%d ", local->data);
local = local->next;
}
}
void freeNode(node **head)
{
node *temp = (*head);
while ((*head) != NULL)
{
(*head) = (*head)->next;
free(temp);
temp = (*head);
}
}
int main()
{
int n, i, flagB = 0, flagM = 0, blnk = 0, mstk = 0;
blnk = mstk = flagB = flagM = 0;
printf("Enter the number of questions: ");
scanf("%d", &n);
char ques[n], ans[n];
if (n == 0)
return 0;
node *headM = (node*) malloc(sizeof(node));
headM->data = 0;
node *nodeM = headM;
node *headB = (node*) malloc(sizeof(node));
headB->next = 0;
node *nodeB = headB;
printf("Enter your given answers: ");
for (i = 0; i < n; ++i)
{
scanf("%s", &ques[i]);
}
ques[n] = '\0';
fflush(stdin);
printf("Enter the solution: ");
for (i = 0; i < n; ++i)
{
scanf("%s", &ans[i]);
}
ans[n] = '\0';
fflush(stdin);
for (i = 0; i < n; ++i)
{
if (ques[i] == '.')
{ ++blnk;
if (flagB == 0)
{
nodeB->data = i + 1;
nodeB->next = NULL;
flagB = 1;
continue;
}
nodeB->next = (node*) malloc(sizeof(node));
nodeB = nodeB->next;
nodeB->data = i + 1;
nodeB->next = NULL;
}
else if (ques[i] != ans[i])
{ ++mstk;
if (flagM == 0)
{
nodeM->data = i + 1;
nodeM->next = NULL;
flagM = 1;
continue;
}
nodeM->next = (node*) malloc(sizeof(node));
nodeM = nodeM->next;
nodeM->data = i + 1;
nodeM->next = NULL;
//flagM = 1; //You made a mistake here
}
}
nodeM = headM;
nodeB = headB;
printf("Your result:\n\tMistakes: %d\n\tBlanks: %d\n", mstk, blnk);
printf("Your mistakes are following question numbers:\n");
if (mstk != 0)
printNode(headM);
else
printf("No Mistakes\n");
printf("\nYour blanks are following question numbers:\n");
if (blnk != 0)
printNode(headB);
else
printf("No Blanks\n");
freeNode(&headM);
freeNode(&headM);
return 0;
}

Related

Memory access violations when trying to read from structs inside of other structs

I am having trouble figuring out how to do this correctly. I have a linked list of nodes then those nodes have pointers put into an array contained in that node. These nodes make up a sort of one-way graph between the nodes. I must then traverse the nodes randomly until the node "Home" is reached.
The main issue I'm having is assigning the graph nodes into the list nodes. I want the function to take in the head of the list, the names of the nodes and the weight (cost to travel between nodes). I'm not sure how to do this correctly and I don't know what I did but I think there's an infinite loop somehow. Any help is greatly appreciated.
The input file is structured as such:
Applebees
GroundRound
BlueMoose
DrunkenNoodle
Home
STOP
Applebees BlueMoose 10
Applebees DrunkenNoodle 13
GroundRound Applebees 2
GroundRound DrunkenNoodle 7
GroundRound Home 52
STOP STOP 0
GroundRound
Ignore the print statements in graphInsert() those are me trying to debug the loops.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
struct graphNode {
char name[100]; // Establishment name
int arcCnt; // Number of outgoing arc from this node
int weights[10]; // Weights of each outgoing arc from this node
struct graphNode* arcs[10]; // Holds other graph nodes that are connected to this node (this node is source)
};
struct listNode {
char name[100]; // Establishment name
struct listNode* next;
struct graphNode* graph; // Pointer into graph
};
void listInsert(struct listNode **head, char name[100]) {
// setup new nodes
struct graphNode* newGraph = (struct graphNode*)malloc(sizeof(struct graphNode));
for (int i = 0; i < 100; i++) {
newGraph->name[i] = name[i];
}
for (int i = 0; i < 10; i++) {
newGraph->arcs[i] = NULL;
}
newGraph->arcCnt = 0;
struct listNode* newNode = (struct listNode*)malloc(sizeof(struct listNode));
for (int i = 0; i < 100; i++) {
newNode->name[i] = name[i];
}
newNode->next = NULL;
newNode->graph = newGraph;
// check if head is NULL
if (*head == NULL) {
*head = newNode;
return;
}
// if the list is populated then add the node to the end
struct listNode* current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
void graphInsert(struct listNode** head, char src[100], char dst[100], int weight) {
struct listNode* srcNode = *head;
printf("CALL:");
while (srcNode->next != NULL) { // loop through list to find src
printf("%s %s", srcNode->name, src);
if (strcmp(srcNode->name, src) == 0) { // when it finds the name, find the dst update the graph node data
printf("FOUND");
struct listNode* dstNode = *head;
while (dstNode->next != NULL) { // this loop is to find the pointer to the dst node
printf(" %s %s", dstNode->name, dst);
if (strcmp(dstNode->name, src) == 0) { // when it finds name finally update all the info
printf("FOUND");
// assign the new arc to the right spot based on arcCnt (how many arcs there are), then return to exit the loops
srcNode->graph->arcs[srcNode->graph->arcCnt] = dstNode->graph;
srcNode->graph->weights[srcNode->graph->arcCnt] = weight;
srcNode->graph->arcCnt++;
return;
}
dstNode = dstNode->next;
}
}
srcNode = srcNode->next;
}
}
int main(){
srand(2021);
// setup variables
struct listNode* head = NULL;
struct graphNode* sourceNode = NULL;
FILE* data = fopen("./hw10.data", "r");
int i = 0;
int section = 1; // flag to read the file correctly
// this loop reads the file
while (1) {
char name[100];
char name2[100];
int weight = 0;
if (section == 1) { // reads the first section
fscanf(data, "%100s", name);
if (strcmp(name, "STOP") == 0) { // if end of section then increment section counter
section++;
} else { // if its not the end of the section then add the name to the linked list
listInsert(&head, name);
}
} else if (section == 2) { // reads the first section and builds the graph
fscanf(data, "%100s %100s %d", name, name2, &weight);
if (strcmp(name, "STOP") == 0) { // if end of section then increment section counter
section++;
} else {
//graphInsert(&head, name, name2, weight);
}
} else if (section == 3) { // this section only reads one line and gets the
char tmp[100];
fscanf(data, "%100s", tmp);
struct listNode* current = head;
while (current->next != NULL) { // loop through to find the right node for the name
if (strcmp(current->name, tmp) == 0) { // if names are equal update the node
sourceNode = current->graph;
break;
}
current = current->next;
}
}
if (feof(data)) break;
i++;
}
// debug print data
printf("\n");
struct listNode* current = head;
while (current != NULL) {
printf("%s\n", current->name);
current = current->next;
}
printf("\n");
// starting node
printf("%s ", sourceNode->name);
// now walk through the graph from sourceNode until we reach the node "Home"
int totalWeight = 0;
i = 0;
while (i < 100) {
char* tmp = sourceNode->name;
if (strcmp(tmp, "Home") == 0) { // if were home then exit program
// ending node and cost
printf("%s %d", sourceNode->name, totalWeight);
return 0;
} else { // if were not home then keep looping
int index = (rand() % sourceNode->arcCnt); // Generates random number between 0 and sourceNode->arcCnt
sourceNode = sourceNode->arcs[index];
//printf("Going to: %s, Index: %d", sourceNode->name, totalWeight);
}
i++;
}
return 0;
}

Linked list being overwritten instead of attached to another linked list

This is written in C.
I'm trying to take user input and use it to create/add to a linked list, which I point to with struct Node *dict; Everything is accomplished using global memory.
Creating a new linked list works fine, but when the user tries to add to the linked list, it overwrites the extant linked list.
Here's my code for adding to the list (words is an array of nodes to be appended to the list):
if (dict == NULL) { // If previous list does not exist, global dict pointer should point to node array
dict = words;
} else { // Else find end of current linked list and point it to the new list
struct Node *head = dict;
while (head->next != NULL) {
head = head->next;
}
head->next = words;
}
When I create a list with the words "apple orange peach," for example, when I print the list, I get the output "apple orange peach." But then when I add "pear" to the list, "apple orange peach" is overwritten and I only see the output "pear," instead of "apple orange peach pear."
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
//// GUI Stuff ////
void drawDashedLine() {
for (int i = 0; i < 30; i++) {
printf("-");
}
printf("\n");
}
void drawDottedLine() {
for (int i = 0; i < 30; i++) {
printf(".");
}
printf("\n");
}
void drawArrowLine() {
for (int i = 0; i < 30; i++) {
printf(">");
}
printf("\n");
}
void drawStarLine() {
for (int i = 0; i < 30; i++) {
printf("*");
}
printf("\n");
}
struct Node {
int length;
char word[5];
struct Node * next;
};
// Pointer to global linked list dictionary
struct Node *dict;
struct Node *newDict;
void printDict() {
drawDottedLine();
struct Node * head = dict;
while (head != NULL) {
printf("%s\n", head -> word);
head = head -> next;
}
drawDottedLine();
return;
}
void alphabetizeDict() { // Bubble sort
//printf("%p --- %p\n", dict, dict->next);
struct Node * head = dict;
if (head == NULL) {
return;
}
struct Node * ptr2 = NULL;
int swapped = 1;
while (swapped) {
swapped = 0;
head = dict;
while (head -> next != ptr2) {
char * temp1 = strdup(head -> word);
char * temp2 = strdup(head -> next -> word);
strupr(temp1);
strupr(temp2);
if (strcmp(temp1, temp2) > 0) {
char temp[5];
strcpy(temp, head -> word);
strcpy(head -> word, head -> next -> word);
strcpy(head -> next -> word, temp);
swapped = 1;
}
head = head -> next;
}
ptr2 = head;
}
return;
}
void createDict() {
// To hold the string entered by the user
char str[5000];
// Holds 1000 words, each up to 5 characters long (4 plus a NULL char)
char newString[1000][5];
printf("\n");
drawArrowLine();
printf("Enter word(s): \n");
fgets(str, sizeof str, stdin);
int i, j, ctr;
j = 0;
ctr = 0; // ctr to iterate through words, j to iterate through letters
for (i = 0; i <= (strlen(str)); i++) {
if (str[i] == ' ' || str[i] == '\0') { // This is whitespace. add null character to terminate string. Start next word
newString[ctr][j] = '\0';
ctr++;
j = 0;
} else { // Else add letter to string
newString[ctr][j] = str[i];
j++;
}
}
for (int i = 0; i < ctr; i++) {
struct Node n;
n.length = strlen(newString[i]);
int c = 0;
char sub[5];
// Only use word's first four letters
while (c < strlen(newString[i]) && c < 4) {
sub[c] = newString[i][c];
c++;
}
sub[c] = '\0';
strcpy(n.word, sub);
n.next = NULL;
if (dict == NULL) {
dict = &n;
} else {
n.next = dict;
dict = &n;
}
}
// alphabetizeDict();
printf("Word(s) added succesfully\n");
drawArrowLine();
printf("\n");
return;
}
void destroyDict() {
printf("Starting new dictionary......\n");
while (dict != NULL) {
struct Node * temp = dict;
dict = dict -> next;
temp -> next = NULL;
}
}
void caseInsensSearch(char * searchTerm) {
for (int i = 0; searchTerm[i]; i++) {
searchTerm[i] = tolower(searchTerm[i]);
}
struct Node * head = dict;
int index = 0;
while (head != NULL) {
char lowercaseWord[5];
for (int i = 0; head -> word[i]; i++) {
lowercaseWord[i] = tolower(head -> word[i]);
}
if (strcmp(lowercaseWord, searchTerm) == 0) {
printf("Found %s at index %i\n", head -> word, index);
drawDashedLine();
return;
}
head = head -> next;
index++;
}
printf("Sorry, I couldn't find %s in your dictionary.\n", searchTerm);
drawDashedLine();
return;
}
void caseSensSearch(char * searchTerm) {
struct Node * head = dict;
int index = 0;
while (head != NULL) {
if (strcmp(head -> word, searchTerm) == 0) {
printf("Found %s at index %i\n", head -> word, index);
drawDashedLine();
return;
}
head = head -> next;
index++;
}
printf("Sorry, I couldn't find %s in your dictionary.\n", searchTerm);
drawDashedLine();
return;
}
void search() {
int isSens;
drawDashedLine();
printf("Enter 1 for Case sensitive\n2 for case insensitive\n");
drawDashedLine();
scanf("%d", & isSens);
while (isSens < 1 || isSens > 2) {
printf("Please enter a number between 1 and 2:\n");
scanf("%d", & isSens);
}
drawDashedLine();
printf("Enter a word to search for:\n");
char searchTerm[5];
scanf("%s", searchTerm);
searchTerm[4] = '\0';
if (isSens == 1) {
caseSensSearch(searchTerm);
} else {
caseInsensSearch(searchTerm);
}
}
int promptUser() {
drawStarLine();
printf("1) Search for a word\n2) Add word(s)\n3) Print dictionary\n4) Start new dictionary\n5) Exit\n");
drawStarLine();
printf("\nEnter a number between 1 and 5:\n");
int choice;
scanf("%1d", & choice);
while (choice < 1 || choice > 5) {
printf("Please enter a number between 1 and 5:\n");
scanf("%d", & choice);
}
return choice;
}
int main() {
for (;;) {
int choice = promptUser();
fflush(stdin);
if (choice == 1) {
search();
} else if (choice == 2) {
createDict();
} else if (choice == 3) {
printDict();
} else if (choice == 4) {
destroyDict();
} else if (choice == 5) {
return 0;
}
}
return 1;
}
I've spent some time diagnosing this problem for you. The problem statement is bizarre... An array of words could be sorted (even with library qsort()) and grow to the fill the array to the brim, but you claim this must use both a linked list and a global "object pool" that is not dynamically allocated...
Here's some code I've compiled BUT NOT TESTED...
It should be simple to follow and expand to accommodate your requirements.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node { // use 'typdef'. Less typing
char word[5]; // VERY SHORT WORDS guaranteed
struct Node *next;
} Node_t;
Node_t dict[ 1000 ]; // global data space
int nextNode = 0;
void printDict() { // traverse LL outputting value(s)
for( Node_t *pn = dict; pn; pn = pn->next )
puts( pn->word );
}
void addNode( char *data ) {
if( nextNode + 1 >= sizeof dict/sizeof dict[0] )
return; // Fixed size cannot grow.
Node_t *pn = &dict[ nextNode ];
strcpy( pn->word, data ); // "apple" WON'T fit
nextNode++;
//EDIT:
// This is not correct.
// See code block below for correction
if( nextNode +1 >= sizeof dict/sizeof dict[0] )
pn->next = NULL;
else
pn->next = &dict[ nextNode ];
}
void createDict() {
char str[5000]; // one lo-o-o-ong input string of short words
printf( "Enter word(s): \n" );
fgets( str, sizeof str, stdin );
// chop words on spaces (or tabs) and store to LL
for( char *cp = str; ( cp = strtok( cp, " \t" ) ) != NULL; cp = NULL )
addNode( cp );
}
void destroyDict() { // super simple!
memset( dict, 0, sizeof dict );
nextNode = 0;
// return; // Do not need those return(s) before final closing brace.
}
80% of any problem is the clear understanding of what the problem is to begin with.
EDIT: Realising the code must 'straddle' both array and LL, the above was not exactly correct. Below is the necessary fix to conform with a LL having a NULL next pointer at its 'tail' node.
void addNode( char *data ) {
if( nextNode + 1 >= sizeof dict/sizeof dict[0] )
return; // Fixed size cannot grow.
strcpy( dict[ nextNode ].word, data ); // "apple" WON'T fit
if( nextNode ) // at node 1 or greater
dict[ nextNode - 1 ].next = &dict[ nextNode ];
nextNode++;
}
try this
if (dict == NULL) { // If previous list does not exist, global dict pointer should point to node array
dict = words;
} else { // Else find end of current linked list and point it to the new list
struct Node *head = dict;
while (head->next != NULL) {
head = head->next;
}
struct Node *ptr = NULL;
ptr->length = strlen(word);
strcpy(ptr->word, sub);
ptr->next = NULL;
head->next = ptr;
}

segmentation fault in a linked list while loop?

I'm trying to setup a graph in C. I tried the graph with user input and it works perfectly. However, i am trying to implement a read from file. The last else statement is where the error is coming from because when i commented it out it compiles without any problems. I have included a comment over the block i think that has the problem. Please let me know if there is anything else needed for this question.
#include <stdio.h>
#include <stdlib.h>
struct node{
int data;
struct node* next;
};
//int counter and mainVertex would be used to determine if graph is connected.
// void graphConnection(){
//
//
//
//
//
//
// }
char* deblank(char* input)
{
int i,j;
char *output=input;
for (i = 0, j = 0; i<strlen(input); i++,j++)
{
if (input[i]!=' ')
output[j]=input[i];
else
j--;
}
output[j]=0;
return output;
}
struct node *G[1000];
int counter = 0;
char *mainVertex;
void readingEachLine(){
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
//Read file and exit if fail
fp = fopen("test.txt", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
line = deblank(line);
int i = 0;
struct node* cursor = malloc(sizeof(struct node));
struct node* secondcursor = malloc(sizeof(struct node));
struct node* tempitem;
while(line[i] != '\n'){
//If its the first of the line look into the array and set struct cursor to the corresponding
//array position
if (i == 0){
mainVertex[counter] = line[0];
int convertor = line[i] - '0';
cursor = G[convertor];
counter++;
}
//if its not the first, then set a struct with that number as data
else{
tempitem = malloc(sizeof(struct node));
int convertor = line[i] - '0';
tempitem->data = convertor;
tempitem->next = NULL;
}
//if there is no element connected to the struct in array, connect the tempitem
if (cursor->next == NULL){
cursor->next = tempitem;
}
//If there are already connected elements, loop until the end of the linked list
//and append the tempitem
//ERROR: I GET SEGMENTATION FAULT FROM HERE. TRIED AFTER COMMENTING IT OUT
else{
secondcursor = cursor;
while(secondcursor->next != NULL){
secondcursor = secondcursor->next;
}
secondcursor->next = tempitem;
}
i++;
}
printf("\n");
}
}
int main(void){
for (int i = 1; i < 1000; i++)
{
G[i]= malloc(sizeof(struct node));
G[i]->data = i;
G[i]->next = NULL;
}
readingEachLine();
}
EDIT: This is how the text file looks like:
1 3 4
2 4
3 1 4
4 2 1 3
Your code has several misconceoptions:
Apparently, you can have a maximum of 1,000 nodes. You have an array G of 1,000 head pointers to linked lists. Don't allocate memory for all 1,000 nodes at the beginning. At the beginning, all lists are empty and an empty linked list is one that has no node and whose head is NULL.
In your example, cursor is used to iterate oer already existing pointers, so don't allocate memory for it. If you have code like this:
struct node *p = malloc(...);
// next use of p:
p = other_node;
you shouldn't allocate. You would overwrite p and lose the handle to the allocated memory. Not all pointers have to be initialised with malloc; allocate only if you create a node.
Your idea to strip all spaces from a line and then parse single digits will fail if you ever have more then 9 nodes. (But you cater for 1,000 node.) Don't try to parse the numbers yourself. There are library functions for that, for example strtol.
It is not clear what mainVertex is supposed to be. You use it only once, when you assign to it. You treat it like an array, but it is a global pointer, initialised to NULL. When you dereference it, you get undefined behaviour, which is where your segmentation fault probably comes from.
Here's a program that does what you want to do. (It always inserts nodes at the head for simplicity and it should have more allocation checks.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum {
maxNodes = 1000
};
struct node{
int data;
struct node* next;
};
struct node *G[maxNodes];
size_t nnode = 0;
int read_graph(const char *fn)
{
FILE * fp;
char * line = NULL;
size_t len = 0;
fp = fopen(fn, "r");
if (fp == NULL) return -1;
while (getline(&line, &len, fp) != -1) {
char *p;
char *end;
int id;
int n;
id = strtol(line, &end, 10);
if (end == line) continue;
if (id < 1 || id > maxNodes) break;
if (id > nnode) nnode = id;
id--;
p = end;
n = strtol(p, &end, 10);
while (p != end) {
struct node *nnew = malloc(sizeof(*nnew));
nnew->data = n - 1;
nnew->next = G[id];
G[id] = nnew;
p = end;
n = strtol(p, &end, 10);
}
}
fclose(fp);
free(line);
return 0;
}
int main(void)
{
if (read_graph("test.txt") < 0) {
fprintf(stderr, "Couldn't gread raph.\n");
exit(1);
}
for (int i = 0; i < nnode; i++) {
struct node *p = G[i];
if (p) {
printf("%d:", i + 1);
for (; p; p = p->next) {
printf(" %d", p->data + 1);
}
puts("");
}
}
for (int i = 0; i < nnode; i++) {
struct node *p = G[i];
while (p) {
struct node *old = p;
p = p->next;
free(old);
}
}
return 0;
}

hashtable printing slightly out of order

I'm trying to create a basic hash table in c that takes in integers. I'm trying to get it to print the numbers 1-10, in order. Everything compiles and seems fine when I input integers, but when I use the printlist function I made, it print 10,1,2,3,4,5,6,7,8,9. I've tried for hours but I can't figure out what's causing it.
#include <stdlib.h>
#include <stdio.h>
typedef struct node {
struct node* next;
int data;
}node;
void printlist(node *ht[]);
node* insert_node(node *ht[]);
int main() {
int index = 0;
int input;
int option;
node* ht[10] = { NULL };
do {
printf("Press 1 to input a node\n");
printf("Press 2 to print the list\n");
printf("Press 3 to exit:\n");
printf("Select Option: ");
scanf("%i", &option);
if (option == 1) {
insert_node(ht);
continue;
}
if (option == 2) {
printlist(ht);
}
} while (option != 3);
}
void printlist(node* ht[]) {
node *prvptr;
node *curptr;
int j = 9;
int index = 0;
for (index = 0; j >= index; index++) {
curptr = ht[index];
curptr = curptr->next;
while (curptr != NULL) {
printf("%i\n", curptr->data);
curptr = curptr->next;
break;
}
}
}
node* insert_node(node* ht[]) {
node *newptr;
node *curptr;
node *prvptr;
node *head;
int count = 0;
int choice;
int index = 0;
int input = 0;
printf("Input negative 1 to cancel\n");
printf("What number would you like to add to the list?: ");
scanf("%i", &input);
index = input % 10;
while (input != -1) {
newptr = (node*)malloc(sizeof(node)); // creates a node for the input data
newptr->data = input;
newptr->next = NULL;
if (ht[index] == NULL) { // if there is no head
ht[index] = (node*)malloc(sizeof(node));
ht[index]->data = NULL;
ht[index]->next = newptr;
count++;
}
else {
curptr = ht[index];
while (curptr->next != NULL) {
prvptr = curptr;
curptr = curptr->next;
if (curptr->data > input) { // if in-between two nodes
prvptr->next = newptr;
newptr->next = curptr;
break;
}
else if (curptr->next == NULL) { // if at the end of the list
curptr->next = newptr;
break;
}
}
}
printf("Input negative 1 to cancel\n");
printf("What number would you like to add to the list?: ");
scanf("%i", &input);
index = input % 10;
}
return ht;
}
Your index calculation is index = input % 10;. The number 10, mod 10, is 0, so it goes in the first index (index 0) of your table, before 1-9 (which would go in indices 1 through 9). Since your printer prints the buckets in order from index 0 to 9 inclusive, 10 is output first.
The nature of hash tables is to have limited ordering (most languages and hash table libraries give no guarantees at all on the iteration order of a hash table); I wouldn't be bothered by 10 happening to appear first in the output.
Just as #ShadowRanger mentioned, it is not wrong for the 10 to come out first.
Instead, I see another error in your printlist code :
while (curptr != NULL) {
printf("%i\n", curptr->data);
curptr = curptr->next;
break;
}
the break statement should not be there, you will end up printing just one of your elements per hash value.

Infinite loops with a linked list

I'm working on a program that takes an input of numbers from stdin and computes the median of the sequence and prints it out as a float. I'm currently getting an infinite loop in the function
len(struct node *)
at the for loop and I'm not sure why.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
float *val;
struct node *next;
};
int len(struct node *list) {
int i = 0;
struct node *temp = list;
for (i = 0; temp != NULL; i++) {
temp = temp->next;
}
return i;
}
float median(int size, struct node list) {
struct node temp = list;
int i = 0;
if (size == 1) {
return *temp.val;
} else
if (size == 2) {
return (*(temp.val) + *(temp.next->val)) / 2;
} else {
if (size / 2 == 1) {
for (i = 3; i != (size / 2) - 1; i++) {
temp = *(temp.next);
}
return *temp.val;
} else {
for (i = 3; i != (size / 2); i++) {
temp = *(temp.next);
}
return (*(temp.val) + *(temp.next->val)) / 2;
}
}
}
int main() {
struct node *tmpnode;
tmpnode = malloc(sizeof(struct node));
tmpnode->next = NULL;
struct node *list = NULL;
list = tmpnode;
float temp = 0;
int err = 0;
int size = 0;
while ((err = scanf("%f", &temp)) != EOF) {
if (err < 1) {
fprintf(stderr, "Error: non-integer character inputted\n");
return 1;
}
tmpnode->val = &temp;
tmpnode->next = list;
list = tmpnode;
}
size = len(list);
if (size == 0) {
fprintf(stderr, "Error: no inputs found");
return 1;
}
printf("%f\n", median(size, *list));
return 0;
}
Edit: I've fixed the infinite loop, but now I'm getting a segfault at temp = *(temp.next) in median(). Do I need to allocate for temp?
You created only one node and assigned next of the node to itself, so this is cause of the infinite loop.
Create new nodes and link them in the input loop.
Assigning address of temp to all nodes is also not good.
Your main() function should be like this:
int main(void){
struct node *tmpnode;
tmpnode = malloc(sizeof(struct node));
if(tmpnode == NULL){
perror("malloc 1");
return 1;
}
tmpnode->next = NULL;
struct node *list = NULL;
list = tmpnode;
float temp = 0;
int err = 0;
int size = 0;
while((err = scanf("%f", &temp)) != EOF){
if(err < 1){
fprintf(stderr, "Error: non-integer character inputted\n");
return 1;
}
tmpnode->val = malloc(sizeof(float));
if(tmpnode->val == NULL){
perror("malloc 2");
return 1;
}
*tmpnode->val = temp;
tmpnode->next = malloc(sizeof(struct node));
if(tmpnode->next == NULL){
perror("malloc 3");
return 1;
}
tmpnode = tmpnode->next;
tmpnode->val = NULL;
tmpnode->next = NULL;
}
size = len(list);
if(size == 0){
fprintf(stderr, "Error: no inputs found");
return 1;
}
printf("%f\n", median(size, *list));
/* code to free the list should be here */
return 0;
}
(I gave input 1 2 3 4 5 and this program's output was 1.500000, which might be wrong)
If you're looking for the median you would have to arrange the nodes in order and get the number that is in the middle.If the number of nods is even and there is no middle you should add the two middlemost numbers and divide them by two.
Is the sequence in order? If not you're miscalculating the median.
Supposing the sequence is in order.
I didn't really understand the usefulness of this statement
if(size/2 == 1)
Maybe you're trying to see if the size is odd. In that case you should do:
> if(size%2 == 1)
Why the list is probably looping might be due to this
for(i = 3; i != (size/2); i++){
temp = *(temp.next);
}
Suppose you pass a 5 to the function size/2=2 (decimal part is lost), so it'll keep on going until an overflow occurs and it actually reaches 2, making your program most probably seg_fault in the process.
Start from i=0, because even though you started from 3 your current node is not the third one but the FIRST ONE.
Good luck hope this helps!!!!

Resources