I am currently in the process of writing a program that acts as a circuit. I have a gate structure that takes a 2D char array in order to hold variable names, yet when I try to access these variable names stored in the array outside of the while loop, the content is empty.
typedef struct Gate
{
kind_t kind;
int size; // size of DECODER and MULTIPLEXER
char **params; // length determined by kind and size (CHANGED FROM INT TO CHAR)
// includes inputs and outputs, indicated by variable numbers
} Gate;
typedef struct Node
{
Gate *data;
struct Node *next;
} Node;
// Linked list of gates & attributes
while (fscanf(fp, "%16s", str) != EOF)
{
if (strcmp(str, "AND") == 0)
{
head = makeGate(fp, head, AND);
length++;
}
else if (strcmp(str, "OR") == 0)
{
head = makeGate(fp, head, OR);
length++;
}
else if (strcmp(str, "NAND") == 0)
{
head = makeGate(fp, head, NAND);
length++;
}
else if (strcmp(str, "NOR") == 0)
{
head = makeGate(fp, head, NOR);
length++;
}
else if (strcmp(str, "XOR") == 0)
{
head = makeGate(fp, head, XOR);
length++;
}
else if (strcmp(str, "NOT") == 0)
{
//head = makeGate(fp, head, NOT);
//length++;
}
else if (strcmp(str, "PASS") == 0)
{
//head = makeGate(fp, head, PASS);
//length++;
}
else if (strcmp(str, "DECODER") == 0)
{
//
}
else if (strcmp(str, "MULTIPLEXER") == 0)
{
//
}
printf("%s\n", head->data->params[2]);
}
// plugs in values to circuit
for (int i = 0; i < 3; i++)
{
printf("Stored string: %s\n", head->data->params[i]);
}
`
Node *makeGate(FILE *fp, Node *head, kind_t inGate)
{
char str[17];
Node *new_node = (Node *)malloc(sizeof(Node)); // Node of linkedlist that contains gate structure
new_node->data = (Gate *)malloc(sizeof(Gate)); // Gate structure that keeps information about a gate
new_node->next = head;
new_node->data->kind = inGate;
new_node->data->size = 3;
new_node->data->params = malloc(3 * sizeof(char*));
for (int i = 0; i < 3; i++)
{
new_node->data->params[i] = malloc(17 * sizeof(char));
}
fscanf(fp, "%16s", str);
new_node->data->params[0] = str;
fscanf(fp, "%16s", str);
new_node->data->params[1] = str;
fscanf(fp, "%16s", str);
new_node->data->params[2] = str;
return new_node;
}
`
The printf statement inside the while loop works perfectly fine and is there purely for testing, however the for loop that prints each value of the array is different and prints nothing.
I tried to fix this multiple times to no avail, I originally found this problem as I noticed that I had gotten memory leak, and when I freed where the memory leak should be, it throws that I am freeing a address that is not malloced.
My only thought is I am somehow losing/skipping a node, but I am out of ideas
The following does not copy data from str into the struct ( you'd need strcpy):
new_node->data->params[0] = str;
What it does is copy the address of str into each element. They all point to the same buffer/string. And, str goes out of scope when the function returns.
You can [and should] just scan into the struct directly.
So, change:
fscanf(fp, "%16s", str);
new_node->data->params[0] = str;
fscanf(fp, "%16s", str);
new_node->data->params[1] = str;
fscanf(fp, "%16s", str);
new_node->data->params[2] = str;
Into:
fscanf(fp,"%16s",new_node->data->params[0]);
fscanf(fp,"%16s",new_node->data->params[1]);
fscanf(fp,"%16s",new_node->data->params[2]);
I have a project about linked lists but I'm having a hard time doing it. The teacher wants me to read a .txt file and create singly linked list from it. After that, I need to reverse odd numbers of every line. Then print it. Here is the code which I used for printing the linked list. But I need help to reverse the odd numbers of each line.
This is the code which I used to print the list:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
char *string;
struct list *next;
};
typedef struct list LIST;
int main(void) {
FILE *fp;
char line[10];
LIST *current, *head;
head = current = NULL;
fp = fopen("data.txt", "r");
while(fgets(line, sizeof(line), fp)){
LIST *node = malloc(sizeof(LIST));
node->string = strdup(line);
node->next =NULL;
if(head == NULL){
current = head = node;
} else {
current = current->next = node;
}
}
fclose(fp);
for(current = head; current ; current=current->next){
printf("%s", current->string);
}
return 0;
}
Here is the content of the .txt file:
10
9,6,11,7,12,18,19,14,15,13
13,14,9,12,15,3,18,20,1,2
4,11,8,17,12,15,20,10,3,16
19,4,11,1,13,17,12,16,20,18
1,6,20,11,13,9,7,16,10,2
12,4,11,16,3,20,9,19,17,15
20,3,10,12,18,2,5,14,15,16
18,19,15,2,6,9,1,3,17,4
7,6,20,1,11,4,3,5,8,16
1,2,16,13,17,10,12,9,4,15
"But I need help to reverse the odd numbers of each line."
There are several other parts that need to be considered before this step can be developed.
Following are suggestions for a functions approach implementation using your problem description. A few items are simply suggestions to simplify the existing code. And a few other steps, are not mentioned as necessary, but should be considered:
Since you are not mandated to use char *string; in your problem description, choose to use a reasonable string length variable that does not require an additional layer of dynamic allocation, such as char string[260]; (or even smaller to fit your input file.) This will greatly simplify the code.
Because the input file is sized with lines ~30 char long, declare the variable line to be at least large enough to contain one line, eg 80 would allow larger values, and still allow enough space, but since memory is cheap, go with the same size as is used in the string member of your linked list.
Move the work of populating each new node to a function. It also will greatly simplify the program, and provide greater readability. Eg: void insert(LIST **head_ref, char *str);
Always test the return of fopen() before attempting to use the file descriptor.
To manipulate the contents of each odd row (eg 1, 3, 5, 7, 9), as numbers, the contents of each line read in from a file as a string, needs to first be converted to a collection of numbers. This suggests an additional member be added to the struct. For example int num[10].
The previous observation implicitly suggests the need of an additional function to parse and convert each comma delimited string into discrete integer values. Perhaps with the prototype: void parseIntArray(LIST **list);
The next and final task also suggests an additional function to reverse the contents of selected array member integer arrays. This one might use a prototype such as: void reverse_odd(LIST **list, size_t size);
Finally, because each node of LIST created required dynamically allocated memory, once finished using LIST, the memory must be given back to the OS to prevent memory leaks. An additional function to do this could be prototyped: void freeList(LIST **head);
Following are the main() function and preceding support declarations etc. It is intended here to illustrate the above suggested steps, and the benefits of breaking down a bigger problem into smaller problems, then implementing each smaller solution to support the whole. Benefits include for example readability and maintainability and potential re-use of code-base, (Note the similarity of argument lists in each supporting function.):
#define MAX_STRLEN 260 //use mnemonic values to avoid magic numbers in code
struct list {
char string[MAX_STRLEN];
int arr[10];
struct list *next;
};
typedef struct list LIST;
//Prototypes of 'smaller' solutions
void insert(LIST **head_ref, char *str);
void parseIntArray(LIST **list);
void reverse_odd(LIST **list, size_t size);
void freeList(LIST **head);
int main(void)
{
FILE *fp;
char line[MAX_STRLEN];
LIST *current, *head;
char *convPtr = NULL;
head = current = NULL;
fp = fopen("data.txt", "r");
if(fp)
{
//consume 1st line
if(fgets(line, sizeof(line), fp));//10
{
sizeArray = strtol(line, &convPtr, 10);
if(errno != ERANGE)
{
while(fgets(line, sizeof(line), fp))
{
//(see implementations of each below)
//create new node, insert num string
insert(¤t, line);
//convert new->string to integers, place in new->array
parseIntArray(¤t);
//reverse 'odd' contents of each array
reverse_odd(¤t, sizeArray);
}
}else{//handle error and leave}
}
fclose(fp);
}else{//handle error and leave}
//At this point in code, entire file is captured into nodes of list.
//use list as needed
//When finished using list, memory must be freed to prevent memory leaks
head = current;
freeList(&head);
return 0;
}
The remaining code segments are the function implementations used above:
void freeList(LIST **head)
{
LIST *tmp;
while (*head != NULL)
{
tmp = (*head);
(*head) = (*head)->next;
free(tmp);
}
}
//create new node, insert num string
void insert(LIST **head_ref, char *str)
{
int *arr = malloc(numNodes * sizeof(*arr));
//allocate node
LIST* new = calloc(1, sizeof(*new));
//put in the data
strcpy(new->string, str);
//Make next of new node as head
new->next = (*head_ref);
//Move the head to point to the new node
(*head_ref) = new;
}
//convert new->string to integers, place in list->array
void parseIntArray(LIST **list)
{
char *tok = NULL;
int i = 0;
int tmp = 0;
char *sArray = strdup((*list)->string);
tok = strtok(sArray, ",\n ");
while(tok)
{
errno = 0;
tmp = atoi(tok);
if(errno == ERANGE)
{
printf("Error converting string to number\nExiting.");
return;
}
(*list)->arr[i] = tmp;
i++;
tok = strtok(NULL, ",\n ");
}
}
//reverse 'odd' contents of list->array
void reverse_odd(LIST **list, size_t size)
{
int *ptr = &((*list)->arr[0]);
int *tmp = malloc(size * sizeof(*tmp));
memset(tmp, -1, size*sizeof(*tmp));
for(int i=0;i<size;i++)
{
if(ptr[i]%2 != 0)
tmp[size-1-i] = ptr[i];
}
for(int i=0;i<size;i++)
{
if(tmp[i] < 0)
{
while((*ptr)%2 != 0 ) ptr++;
tmp[i] = *ptr;
ptr++;
}
}
memcpy((*list)->arr, tmp, size*sizeof(int));
}
This hope this code will do the job.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct line {
struct num *first;
struct line *next;
} LineNode;
typedef struct num {
int num;
int order;
struct num *next;
} NumNode;
int main() {
FILE *fp;
char ch;
int counter = 0;
NumNode *curr_num, *even_ptr, *odd_ptr, *odd_head, *even_head;
LineNode *curr_line, *line_head;
curr_num = even_head = odd_head = even_ptr = odd_ptr = NULL;
line_head = curr_line = NULL;
fp = fopen("data.txt", "r");
if (fp == NULL)
{
return 1;
}
ch = fgetc(fp);
while(ch != EOF){
if (ch >= 48 && ch <= 57)
{
int n = 0;
while (ch != EOF && ch != '\n' && ch >= 48 && ch <= 57)
{
int x = ch - 48;
n = n * 10 + x;
ch = fgetc(fp);
}
NumNode *node = malloc(sizeof(NumNode));
node->num = n;
node->order = counter;
node->next =NULL;
if (n % 2 == 0){
if(even_head == NULL){
even_head = even_ptr = node;
} else {
even_ptr = even_ptr->next = node;
}
}else{
if(odd_head == NULL){
odd_head = node;
} else {
node->next = odd_head;
odd_head = node;
}
}
counter++;
}
if (ch == '\n' || ch == EOF)
{
NumNode *num_node, *head;
num_node = head = NULL;
even_ptr = even_head;
odd_ptr = odd_head;
counter = 0;
if (even_head != NULL && even_head->order == counter){
head = num_node = even_ptr;
even_ptr = even_ptr->next;
} else {
head = num_node = odd_ptr;
odd_ptr = odd_ptr->next;
}
counter++;
while (even_ptr != NULL)
{
if (even_ptr->order == counter) {
num_node = num_node->next = even_ptr;
even_ptr = even_ptr->next;
}
else if (odd_ptr != NULL) {
num_node = num_node->next = odd_ptr;
odd_ptr = odd_ptr->next;
}
counter++;
}
while (odd_ptr != NULL)
{
num_node = num_node->next = odd_ptr;
odd_ptr = odd_ptr->next;
}
LineNode *node = malloc(sizeof(LineNode));
node->next =NULL;
node->first = head;
if (line_head == NULL)
line_head = curr_line = node;
else
curr_line = curr_line->next = node;
odd_head = even_head = NULL;
counter = 0;
}
ch = fgetc(fp);
}
fclose(fp);
for(curr_line = line_head; curr_line != NULL ; curr_line=curr_line->next) {
for(curr_num = curr_line->first; curr_num != NULL ; curr_num=curr_num->next) {
printf("%d", curr_num->num);
if (curr_num->next != NULL)
printf(",");
}
printf("\n");
}
return 0;
}
I'm trying to finish one of my assignments and I have some issues. I have to make a program that uses struct to create a link list in which I have to add words. If the word is already in the linked list then I just have to update the frequency.
I already have this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct words Words;
struct words{
char *word;
int freq;
Words *next;
};
/*
Inserts a copy of newWord into the list, in lexicographical order. If newWord is already
in the list, increment the freq member of the node. The function returns a pointer to
the list.
*/
Words *addWord(Words *headPtr, char* newWord){
Words *current = headPtr;
if(headPtr == NULL)
{
current->word = newWord;
current->freq = 1;
}
else
{
while(current != NULL)
if(strcmp(headPtr->word, newWord))
{
current->freq++;
return headPtr;
}
else
{
current->word = newWord;
current->freq = 1;
}
}
return headPtr;
}
//prints the words in the list, along with the frequency of each word
void printWords(Words *headPtr){
while(headPtr != NULL)
{
printf("%s: %d", headPtr->word, headPtr->freq);
headPtr = headPtr->next;
}
}
//frees the entire list. Note: Words **headPtr since the headPtr NULL upon return
void deleteList(Words **headPtr){
Words *current = *headPtr;
Words *next;
while(current != NULL)
{
next = current->next;
free(current);
current = next;
}
*headPtr = NULL;
}
int main(){
char word[20];
Words *list = NULL;
scanf("%s", word);
while(!feof(stdin)){
list = addWord(list, word);
scanf("%s", word);
}
printWords(list);
deleteList(&list);
}
There are some problems in your code. See comments embedded into your code:
Words *addWord(Words *headPtr, char* newWord){
Words *current = (Words*) malloc(sizeof(Words)); // Don't malloc here.
// You don't know yet
// whether you need
// a new node or you
// you just need to
// update freq
if(current == NULL) // If current is NULL you have
// serious problems, i.e. you
// are out of memory.
// Did you really intended to do:
// if (headPtr == NULL)
{
current->word = newWord;
*current->next = (*headPtr);
(*headPtr) = *current; // I'm not sure what you try here
// but it seems strange
}
else
{
while(current != NULL)
if(strcmp(headPtr->word, newWord)) // This is not the way to compare
// strings. Two strings compare
// when "strcmp" returns 0.
//
// Further you don't want to
// use headPtr here.
{
current->freq++; // Use of uninitialized value
return; // Missing argument to return
}
else
{
current->word = newWord; // Use of uninitialized value
*current->next = (*headPtr); // Use of uninitialized value
(*headPtr) = *current;
}
}
// Missing return
}
Here is some code to start with:
#define WORD_SIZE 20
struct words{
char word[WORD_SIZE]; // Use a char array
int freq;
Words *next;
};
Words *addWord(Words *headPtr, char* newWord)
{
Words *current = headPtr; // Make a copy of headPtr
Words* new;
if ((current == NULL) || (strcmp(current->word, newWord) > 0))
{
// Insert in front of list
new = malloc(sizeof(Words)); // Allocate memory
if (new == NULL)
{
// oh, dear - out of memory - print an error message and exit
exit(1);
}
strncpy(new->word, newWord, WORD_SIZE); // Make sure not to overflow
// the buffer, so use strncpy
(new->word)[WORD_SIZE-1] = '\0'; // Make sure to zero terminate
new->freq = 1;
new->next = headPtr;
return new;
}
while(1)
{
int cmp = strcmp(current->word, newWord);
if(cmp == 0)
{
current->freq++;
return headPtr;
}
if(cmp < 0)
{
if ((current->next == NULL) || (strcmp(current->next->word, newWord) > 0))
{
// Add code to insert node after current
return headPtr;
}
}
else
{
// This should never happen...
printf("BAD CODE 1\n");
exit(1);
}
current = current->next;
}
}
Based on print statements in the rehashing section, I can see that the same string is getting added to the table multiple times. I believe the problem is in this function, although I can't see where. The print statement below return is never executed, so I know that the function actually executes.
Any ideas on where the problem is, or how I should go about finding it? Thanks. The full code on our repository is here:
https://github.com/csking1/buddhism/blob/master/Finding/hash_tables.c
void add_to_table(HashTable *h, char* str, LinkedList* new){
unsigned int hashval = hash(h, str);
LinkedList *list;
// walk through the table and check for the first free spot, start at hash val and go to the top
for (int i = hashval; i<h->size; i++){
list = h->table[i];
if (list == NULL){
new->next = h->table[i];
h->table[i] = new;
new->string = str;
return;
printf("%s\n", "didn't return");
}
}
// start at the bottom of the table, check for the first free spot up to hash val, then return
for (int i = 0; i < hashval; i++){
list = h->table[i];
if (list == NULL){
new->next = h->table[i];
h->table[i] = new;
new->string = str;
return;
}
}
}
For a full view, here's the string lookup function. This gets called one or two lines above the add_to_table() function, and returns if the string is already there.
LinkedList *lookup_string(HashTable *h, char *str){
LinkedList *list;
unsigned int hashval = hash(h, str);
for (int i = hashval; i < h->size; i++){
list = h->table[i];
if (list == NULL){
return NULL;
}
if (list != NULL){
if (strcmp(str, list->string) == 0){
return list;
}
}
}
for (int i = 0; i < hashval; i++){
list = h->table[i];
if (list == NULL){
return NULL;
}
if (list != NULL){
if (strcmp(str, list->string) == 0){
return list;
}
}
}
return NULL;
}
#pragma warning (disable:4996)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#define NUM_OF_ALPHABET 26
#define MAX_HEAP_SIZE 100
typedef struct _CharFrequency
{
char character;
int frequency;
struct _CharFrequency * next;
}CharFrequency;
typedef CharFrequency* pCharFrequency;
pCharFrequency pHead = NULL;
void initList();
void addNode(char ch);
void printAllNode(pCharFrequency pHead);
int main()
{
int i = 0, cnt = 0;
FILE *pFile;
char readLine[1024], *ptr;
char *token = " \t\n.";
pFile = fopen("C:\\Users\\Home\\Desktop\\dataset.txt", "r");
if (pFile == NULL)
{
printf("File open failed.\n");
return 0;
}
while (fgets(readLine, 1024, pFile) != NULL)
{
ptr = strtok(readLine, token);
while (ptr != NULL)
{
for (i = 0; i < strlen(ptr); i++)
{
addNode(ptr[i]);
}
ptr = strtok(NULL, token);
}
}
printAllNode(pHead);
return 0;
}
void initList()
{
pHead = (CharFrequency*)malloc(sizeof(CharFrequency));
if (!pHead)
{
printf("Fault\n");
return;
}
pHead->character = '\0';
pHead->frequency = 0;
pHead->next = NULL;
}
void addNode(char ch)
{
int i = 0;
pCharFrequency pNode = NULL;
pCharFrequency pCurrent= NULL;
if (isalpha(ch) == 0)
return;
if (ch >= 'A' && ch <= 'Z')
ch = ch + 32;
printf("%c ", ch);
for (pCurrent = pHead; pCurrent != NULL ; pCurrent = pCurrent->next)
{
if (pCurrent->character == ch)
{
pCurrent->frequency++;
}
else
{
pNode = (CharFrequency*)malloc(sizeof(CharFrequency));
pNode->frequency = 0;
pNode->next = NULL;
pNode->character = ch;
pNode->frequency++;
pCurrent->next = pNode;
}
}
pNode = (CharFrequency*)malloc(sizeof(CharFrequency));
pNode->frequency = 0;
pNode->next = NULL;
pNode->character = ch;
pNode->frequency++;
pCurrent->next = pNode;
}
void printAllNode(pCharFrequency pHead)
{
pCharFrequency pCurrent;
pCurrent = pHead;
pCurrent = pHead;
while (pCurrent->next != NULL) {
printf("%c %d", pCurrent->character, pCurrent->frequency);
pCurrent = pCurrent->next;
}
}
I want to build a program that reads txt file, count only alphabet, and count them using linked list. I make struct called CharFrequency to count alphabet.
addNode function gets the character, checks if it's in the list or not, and count them.
It makes error when doing for() in the addNode function.
You need to rethink about the logic inside your addNode method. It is adding a new node every time a character is not found in the list, and even if a match is found,the loop will continue until the last node adding a new node every time.
You could do something like this to get you started and experiment on it to make it more efficient.
pCharFrequency pNode = NULL;
pCharFrequency pCurrent= NULL;
pCharFrequency pTail= NULL;//this will keep track of the last node in the list
//so that we use it to insert a new node
....//your other code
pCurrent = pHead;//start from the head
while (pCurrent!=NULL)
{
if (pCurrent->character == ch)
{
pCurrent->frequency++;
return;//if a match was found, count and return
}
if(pCurrent->next == NULL)
pTail=pCurrent;//save the pointer to the last node in the list if we reach to it
pCurrent=pCurrent->next;//get the next node
}
//if we reach here, then we need to create a new node
pNode = (CharFrequency*)malloc(sizeof(CharFrequency));
if(pNode==NULL)
{
//show error message
return;
}
pNode->frequency = 1;
pNode->next = NULL;
pNode->character = ch;
if(pHead==NULL)
pHead=pNode;//for the very first node,we just assign to head
else
pTail->next = pNode;//otherwise set the last node's next to the node we just created