character strings being mutated somehow - c

I am working on a a small program and it has a tiny logic error which I can't seem to trace. It tracks records input of this form:
time userID weight
It searches a linked list of all previous records to find the most recent one where the userID matches the current userID. It then compares the time and weight and calculates the rate of change in the weight. If the weight has changed abruptly it print "suspicious weight change". If there is not match and the input is valid it simply adds the new record to the list.
I have it working except when the userID is added to the list it seems to overwrite all the previous userID's. So even if a new record is input which has a unique userID, it finds a match, because all the ID's a made the same.
I just need a second pair of eyes to help spot where this is happening, I am new to C so it is probably some newbie mistake. But after 8 hrs of trying to find it, I am desperate for some help!
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define DELIM " " /* the delimiter */
#define MAX_CHANGE (10.0/86400.0) /* 10kg/day */
/* seconds in a day is 24 hours * 60 minutes * 60 seconds */
/* return 0 if the passed strings don't math, 1 otherwise */
/* defines the structure of Node */
struct Node
{
char * id;
float weight;
int time;
struct Node * next;
} *head, *p, *t, *last;
/* Constructor which returns a pointer to a new node*/
struct Node *newNode(int *time, char * id, float *w)
{
/*note malloc returns a pointer */
struct Node *r = (struct Node *)malloc( sizeof(struct Node) );
r->time = *time;
r->id = id;
r->weight = *w;
r->next = NULL;
return r;
}
/* prints the list starting with head */
printList(struct Node * head)
{
while(head != NULL)
{
printf("%d %s %f\n",head->time,head->id,head->weight);
head = head->next;
}
}
main()
{
char line[1024];
int lasttime = 0;
int success;
int timestamp;
int duration;
char userID[1000] = "";
char *token;
char temp[1000];
float weight;
float lastweight;
float change;
float changePerTime;
head = (struct Node*)malloc(sizeof(struct Node));
head->id = "";
head->weight = 0.0;
head->time = 0;
head->next = NULL;
last = head;
/*FILE * f = fopen("C:\\Users\\Chris\\Documents\\School\\York\\Computer Science\\2031 Software Tools\\Labs\\lab3\\testcases\\06.in","r"); */
/* last points to the last node in the list
head is always the same node
p is used to travers the list
t is a pointer the most recent occurrense of a user record
*/
while (fgets(line,1024,stdin) != NULL)
{
userID[0] ='\0'; // resets userID
token = strtok(line, DELIM);
success = sscanf(token,"%d",&timestamp);
if (success < 1 || timestamp == 0)
{
printf("Invalid time\n");
continue;
}
while((token = strtok(NULL,DELIM) ) != NULL && token[0] != '.' && ! isdigit(token[0]) )
{
strcpy(temp,token); //
strcat(temp,DELIM ); // adds space between each token
strcat(userID, temp); // src temp must be a const string, not a pointer
temp[0] = '\0';
}
userID[strlen(userID)-1] = '\0'; //erases the tailing space.
if(strlen(userID) > 179 || !strlen(userID) )
{
printf("Illegal userID\n");
continue;
}
else if(token == NULL || sscanf(token,"%f", &weight) < 1 || weight < 30.0 || weight > 300.0)
{
printf("Illegal weight\n");
continue;
}
else if (lasttime >= timestamp)
{
printf("Nonmonotonic timestamps\n");
continue;
}
else
{
/* sets t to last found user record and sets "last" to the last record*/
for(p = head; p != NULL; p = p->next)
{
if(strcmp(userID,p->id) == 0)
{
t=p;
}
last = p; // set last to last p.
}
if(t == NULL)
printf("OK newuser\n");
else if(t != NULL)
{
duration = timestamp - t->time;
change = weight - t->weight;
changePerTime = change / duration;
if(changePerTime < -MAX_CHANGE || changePerTime > MAX_CHANGE)
printf("Suspiciously large weight change\n");
else
printf("OK\n");
}
/* adds node to end of list */
last->next = newNode(&timestamp,userID,&weight);
printList(head);
}
}
//fclose(f);
}

I can fix the over-writing by changing newNode to:
struct Node *newNode(int *time, char * id, float *w)
{ /*note malloc returns a pointer */
struct Node *r = (struct Node *)malloc( sizeof(struct Node) );
r->time = *time;
r->id = strdup(id);
r->weight = *w;
r->next = NULL;
return r;
}
Note the addition of the call to strdup.

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;
}

Arrange the Polynomial in Canonical Order in C

Let's say I have a Polynomial with 3 variables (x, y, z) that is not necessarily in canonical order and I want it to be in standard form where the leftmost term has the greatest exponent and the rightmost term has the least exponent. For example case:
Original Polynomial:
-7xy⁶ + 9xz - 8y⁷ +x⁷ + 4x⁵y⁴z² + 4xy²z³ + 3xy³
Standard Form:
x⁷ + 4x⁵y³z² - 7xy⁶ + 3xy³ + 4xy²z³ + 9xz - 8y⁷
This can be easily done in Python, but I am in C and I have no idea how it should be done. Here is a sample code where I implement polynomials with struct. To make it look less confusing, I am not displaying the variables. Instead, my format is: x exponent y exponent z exponent coefficient. Example: 4(x^5)(y^3)(z^2) is 5 3 2 4.
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int coeff;
int powX;
int powY;
int powZ;
struct Node* next;
};
void readPolynomial(struct Node** poly) /* ACCEPTS A POLYNOMIAL WITH N TERMS */
{
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
*poly = temp;
int terms;
scanf("%d\n", &terms);
for(int i = 0; i < terms; i++)
{
char entry[200];
fgets(entry, sizeof(entry), stdin);;
char * splitter;
splitter = strtok(entry," ");
temp->powX = atoi(splitter);
splitter = strtok(NULL, " ");
temp->powY = atoi(splitter);
splitter = strtok(NULL, " ");
temp->powZ = atoi(splitter);
splitter = strtok(NULL, " ");
temp->coeff = atoi(splitter);
temp->next = NULL;
if(i != terms-1)
{
temp->next = (struct Node*)malloc(sizeof(struct Node));
temp = temp->next;
temp->next = NULL;
}
}
}
void canonicalPolynomial(struct Node* poly)
{
while(poly != NULL)
{
printf("%d %d %d %d\n", poly->powX, poly->powY, poly->powZ, poly->coeff);
poly = poly->next;
}
}
int main()
{
struct Node* result = NULL;
readPolynomial(&result);
canonicalPolynomial(result);
return 0;
}
Right now, canonicalPolynomial just prints it in the said format, but not yet in canonical order.
Input:
7
1 6 0 -7
1 0 1 9
0 7 0 -8
7 0 0 1
5 3 2 4
1 2 3 4
1 3 0 3
Expected Output:
7 0 0 1
5 3 2 4
1 6 0 -7
1 3 0 3
1 2 3 4
1 0 1 9
0 7 0 -8
UPDATE: Here's my latest code. I get the given test code right, but I miss the hidden ones in our compiler. So far, my code knows when a term has the coefficient 0, it does not print it. What else could I be missing?
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
struct Node
{
float coeff;
int powX;
int powY;
int powZ;
struct Node* next;
};
void readPolynomial(struct Node** poly)
{
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
*poly = temp;
int terms;
fscanf(stdin, "%d", &terms);
getchar();
char entry[999999];
char *splitter;
for(int i = 0; i < terms; i++)
{
fgets(entry, sizeof(entry), stdin);
splitter = strtok(entry," ");
temp->powX = atoi(splitter);
splitter = strtok(NULL, " ");
temp->powY = atoi(splitter);
splitter = strtok(NULL, " ");
temp->powZ = atoi(splitter);
splitter = strtok(NULL, " ");
temp->coeff = atof(splitter);
temp->next = NULL;
if(i != terms-1)
{
temp->next = (struct Node*)malloc(sizeof(struct Node));
temp = temp->next;
temp->next = NULL;
}
}
}
int compareTerms(const struct Node *a, const struct Node *b)
{
int cmp;
cmp = (a->powX > b->powX) - (a->powX < b->powX);
if (cmp != 0) {
return cmp;
}
cmp = (a->powY > b->powY) - (a->powY < b->powY);
if (cmp != 0) {
return cmp;
}
cmp = (a->powZ > b->powZ) - (a->powZ < b->powZ);
return cmp;
}
void sortPolynomialTerms(struct Node **poly)
{
struct Node *head;
unsigned int sublen;
head = *poly;
if (!head) {
return;
}
sublen = 1;
while (1) {
struct Node *tail;
struct Node *p;
struct Node *q;
struct Node *e;
unsigned int plen;
unsigned int qlen;
unsigned int merges;
unsigned int i;
p = head;
head = NULL;
tail = NULL;
merges = 0;
while (p) {
merges++;
q = p;
plen = 0;
for (i = 0; i < sublen; i++) {
plen++;
q = q->next;
if (!q) {
break;
}
}
qlen = plen;
while (plen || (qlen && q)) {
if (!plen || (qlen && q && compareTerms(p, q) < 0)) {
e = q;
q = q->next;
qlen--;
} else {
e = p;
p = p->next;
plen--;
}
if (tail) {
tail->next = e;
} else {
head = e;
}
tail = e;
}
p = q;
}
tail->next = NULL;
if (merges <= 1) {
break;
}
sublen *= 2;
}
*poly = head;
}
void printPolynomial(const struct Node *poly)
{
while (poly)
{
if(poly->coeff != 0)
{
printf("%d %d %d %.3f\n", poly->powX, poly->powY, poly->powZ, poly->coeff);
}
poly = poly->next;
}
}
void canonicalPolynomial(struct Node **poly)
{
sortPolynomialTerms(poly);
printPolynomial(*poly);
}
void addPolynomials(struct Node** result, struct Node* first, struct Node* second)
{
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
temp->next = NULL;
*result = temp;
while(first && second)
{
if(compareTerms(first, second) < 0)
{
temp->coeff = second->coeff;
temp->powX = second->powX;
temp->powY = second->powY;
temp->powZ = second->powZ;
second = second->next;
}
else if(compareTerms(first, second) > 0)
{
temp->coeff = first->coeff;
temp->powX = first->powX;
temp->powY = first->powY;
temp->powZ = first->powZ;
first = first->next;
}
else
{
temp->coeff = first->coeff + second->coeff;
temp->powX = first->powX;
temp->powY = first->powY;
temp->powZ = first->powZ;
first = first->next;
second = second->next;
}
if(first && second)
{
temp->next = (struct Node*)malloc(sizeof(struct Node));
temp = temp->next;
temp->next = NULL;
}
}
while(first || second)
{
temp->next = (struct Node*)malloc(sizeof(struct Node));
temp = temp->next;
temp->next = NULL;
if(second)
{
temp->coeff = second->coeff;
temp->powX = second->powX;
temp->powY = second->powY;
temp->powZ = second->powZ;
second = second->next;
}
else if(first)
{
temp->coeff = first->coeff;
temp->powX = first->powX;
temp->powY = first->powY;
temp->powZ = first->powZ;
first = first->next;
}
}
}
int main()
{
struct Node* first = NULL;
struct Node* second = NULL;
struct Node* result = NULL;
readPolynomial(&first);
readPolynomial(&second);
addPolynomials(&result, first, second);
canonicalPolynomial(&result);
return 0;
}
The problem boils down to sorting a linked list, for which you need a suitable comparison function to determine the sort order for two terms on the list:
int compareTerms(const struct Node *a, const struct Node *b)
{
int cmp;
/* Compare X exponents. */
cmp = (a->powX > b->powX) - (a->powX < b->powX);
if (cmp != 0) {
return cmp;
}
/* Compare Y exponents. */
cmp = (a->powY > b->powY) - (a->powY < b->powY);
if (cmp != 0) {
return cmp;
}
/* Compare Z exponents. */
cmp = (a->powZ > b->powZ) - (a->powZ < b->powZ);
#if 0
if (cmp != 0) {
return cmp;
}
/* Compare coefficients (why not?). */
cmp = (a->coeff > b->coeff) - (a->coeff < b->coeff);
#endif
return cmp;
}
(Change the #if 0 to #if 1 to compare the coefficients if all the exponents are equal.)
The function returns -1 if the first term has lower order than the second, 1 if the first term has higher order than the second, or 0 if they are of equal order.
The comparison function can be used by a function to sort the list of terms. For simplicity, an exchange sort is shown below:
void sortPolynomialTerms(struct Node **poly)
{
while (*poly) {
struct Node **next = &(*poly)->next;
while (*next) {
struct Node *n = *next;
if (compareTerms(*poly, n) < 0) {
*next = n->next;
n->next = *poly;
*poly = n;
} else {
next = &n->next;
}
}
poly = &(*poly)->next;
}
}
The sort function can be used as follows:
void printPolynomial(const struct Node *poly)
{
while (poly)
{
printf("%d %d %d %.3f\n", poly->powX, poly->powY, poly->powZ, poly->coeff);
poly = poly->next;
}
}
void canonicalPolynomial(struct Node **poly)
{
sortPolynomialTerms(poly);
printPolynomial(*poly);
}
The parameter of sortPolynomialTerms and canonicalPolynomial is struct Node **poly because they may modify the pointer to the initial term *poly to point to a different initial term.
BONUS CONTENT
It is probably not worth it for short polynomials, but for polynomials containing many terms to be sorted, a merge sort will be more efficient than the exchange sort implemented above. Based on the sample code "listsort.c" for the page "Mergesort For Linked Lists" by Simon Tatham, the following version of sortPolynomialTerms uses a bottom-up merge sort:
void sortPolynomialTerms(struct Node **poly)
{
/*
* Bottom-up merge sort, based on:
*
* <https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.c>
*
* Original copyright notice for linked source:
*
* This file is copyright 2001 Simon Tatham.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct Node *head; /* head of merged list */
unsigned int sublen; /* maximum length of sub-list */
head = *poly;
if (!head) {
/* The list is empty, so does not need sorting. */
return;
}
/* Start with sub-lists of maximum length 1. */
sublen = 1;
while (1) {
struct Node *tail; /* tail of merged list */
struct Node *p; /* pointer to node in first sub-list */
struct Node *q; /* pointer to node in second sub-list */
struct Node *e; /* pointer to node to add to merged list */
unsigned int plen; /* length of first sub-list */
unsigned int qlen; /* maximum length of second sub-list */
unsigned int merges; /* number of sub-list merges done */
unsigned int i;
/*
* Construct a new merge list by merging one or more pairs
* of sorted sub-lists of length up to `sublen`.
*/
p = head;
head = NULL;
tail = NULL;
merges = 0;
while (p) {
merges++;
/* Step up to `sublen` places along from `p`. */
q = p;
plen = 0;
for (i = 0; i < sublen; i++) {
plen++;
q = q->next;
if (!q) {
break;
}
}
qlen = plen; /* upper bound on length of second sub-list */
/*
* Merge the two sub-lists onto the end of the new merge list.
*/
while (plen || (qlen && q)) {
/* Decide where the next element to merge comes from. */
if (!plen || (qlen && q && compareTerms(p, q) < 0)) {
/* Take next element from second list `q`. */
e = q;
q = q->next;
qlen--;
} else {
/* Take next element from first list `p`. */
e = p;
p = p->next;
plen--;
}
/* Add next element to the merged list. */
if (tail) {
tail->next = e;
} else {
head = e;
}
tail = e;
}
/* Advance to the next pair of sub-lists. */
p = q;
}
/* Terminate the new merge list. */
tail->next = NULL;
/* Finish when no more than one pair of sub-lists needed merging. */
if (merges <= 1) {
break;
}
/* Double the maximum length of the sub-lists for the next merge. */
sublen *= 2;
}
/* Update the link to the first node of the list. */
*poly = head;
}
The absolute simplest way of sorting a linked list is to convert it to a regular list, use qsort and then convert back. Something like this:
// Converts a linked list to array
//
// Assumes that memory is already allocated for dest and that src is a proper
// linked list where the last element has NULL assigned to ->next
void linkedListToArray(struct Node *dest, struct Node *src) {
while(src) {
*dest = src;
dest++;
src = src->next;
}
}
You should redesign your code to be more modular. You should study implementations of linked lists in general, but you should really write a function similar to this:
void append(struct Node **list, int coeff, int px, int py, int pz) {
struct Node *node = malloc(sizeof *node);
*node = (struct Node) {.coeff = coeff, .powX = px, .powY = py, .powZ = pz };
if(*list == NULL) {
*list = node;
} else {
while((*list)->next) (*list) = (*list)->next;
(*list)->next = node;
}
}
You should use it in readPolynomial but also in the function converting an array to a linked list.
void arrayToLinkedList(struct Node **list, struct Node *arr, size_t size) {
for(size_t i = 0; i < size; i++)
append(list, &arr[i]);
}
When you have the above, you just need to write the compare function for quicksort. Read the documentation about how that is done. And then you can do this:
struct Node *pol;
// Init code
struct Node *arr = malloc(sizeof *arr * size); // Calculate size before somehow
linkedListToArray(arr, pol);
qsort(arr, size, sizeof *arr, cmp);
struct Node *newPol;
arrayToLinkedList(&newPol, arr);
Note that I have skipped all error checking to keep the code short.
Old answer. I misread the question, but OP mentioned they liked the answer in comments. The below says it is how to make a polynomial to standard form, but the question I'm really answering is how to normalize a polynomial.
To convert it to standard normalized form, you basically need to do two things
Find the term with highest degree
Divide all terms with the coefficient of the term with highest degree.
Determining the term with highest degree is ambiguous when dealing with more than one variable, since the degree simply is Node::powX + Node::powY + Node::powZ. But in any case, you would need to define a function that takes a whole polynomial and returns the node with highest degree according to some definition. Here is ONE way to do it:
int degree(struct Node *term) {
return term->powX + term->powY + term->powZ;
}
struct Node *getTermWithHighestDegree(struct Node *pol) {
struct Node *ret = pol;
while(pol) {
if(degree(pol) > degree(ret)) ret = pol;
pol = pol->next;
}
}
Then simply do:
void convertToNormalizedForm(struct Node *pol) {
struct Node *term = getTermWithHighestDegree(pol);
int coeff = term->coeff;
while(pol) {
pol->coeff /= coeff;
pol = pol->next;
}
}
Do however note that you might run into several issues because you're storing the coefficients as integers. You might want to change to a float type.

Creating a singly linked list from a .txt file and reversing odd numbers of each line in C

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(&current, line);
//convert new->string to integers, place in new->array
parseIntArray(&current);
//reverse 'odd' contents of each array
reverse_odd(&current, 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;
}

How would checking if a value in a data structure equals NULL return a segmentation fault?

I am trying to load a hash table of node*(s)-
typedef struct node{
char word[LENGTH+1];
struct node* next;
}node;
(don't worry about length, it is defined in the file that calls this)
-into memory, but this:
// make hash table
node* hashtable[729];
node* new_node = malloc(sizeof(node));
node* cursor = NULL;
int bucket;
while(sscanf(dictionary,"%s",new_node->word) != 0)
{
bucket = hash(new_node->word);
cursor = hashtable[bucket];
while(cursor->next != NULL)
{
cursor = cursor->next;
}
cursor->next = new_node;
}
return true;
keeps turning up to be a segmentation fault (specifically the condition of the while loop). I am baffled, what is going on? Thank you in advance to any who helps! I really appreciate your help!
You need to allocate memory for each node that is going into your hash table. How's about something like the following:
/* make hash table */
node* hashtable[729];
/* initialise all buckets to NULL */
memset(hashtable, 0, sizeof(node*)*729);
node new_node; /* Use a stack node for the temporary */
new_node.next = NULL;
node** cursor = NULL;
int bucket;
while(sscanf(dictionary,"%s",new_node.word) != 0)
{
bucket = hash(new_node.word);
cursor = &hashtable[bucket];
while(*cursor != NULL)
{
cursor = &(*cursor)->next;
}
if ((*cursor = malloc(sizeof(node))) != NULL)
/* Copy from temporary to hashed node. Assumes structure is 'flat' */
**cursor = new_node;
else {
/* panic! */
}
}
return true;
Edit:
I've refactored some code and produced a standalone example that compiles and runs, For simplicity, I've employed a totally bogus hash function and reduced the number of buckets to fit its output of 0-25. I've tried to split out the hashtable 'object' and started the effort to be a little more disciplined to avoid buffer overruns, etc.
For the traversal of the linked list of nodes in a bucket of the hashtable, I've included two versions--one that uses the node** (pointer to a pointer) and another that doesn't--in an attempt to demonstrate the use of the double star. Change the #if 1 to #if 0 to use the "single star" version.
I hope that, collectively, these changes help clarify (more than they obscure) the original purpose, although I apologise for the verboseness of the code that follows:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define LENGTH 64
typedef struct node {
char word[LENGTH+1];
struct node * next;
} node;
typedef struct hashtable {
node * table[26];
} hashtable;
/* The cleverest 'hashing' function in the world ever! */
int hash(const char * str) {
if (str && str[0]) return tolower(str[0]) - 'a';
return 0;
}
/* Allocate a new node and initialise it with the given word */
node * node_create(const char * word) {
node * nd = NULL;
if (word && (nd = malloc(sizeof(node)))) {
strncpy(nd->word, word, sizeof(nd->word)-1);
nd->word[sizeof(nd->word) - 1] = '\0';
nd->next = NULL;
}
return nd;
}
/* Set all the buckets' pointers to NULL */
void hashtable_init(hashtable * ht) {
if (ht) memset(ht, 0, sizeof(hashtable));
}
/* Place the given node into the hashtable, taking responsibility for it */
void hashtable_insert_node(hashtable * ht, node * nd) {
if (ht && nd) {
#if 1 /* More succint version using node** */
/* Identify the bucket this node should go into */
node ** cursor = ht->table + hash(nd->word);
/* Append this node to this bucket's list of nodes */
while (*cursor != NULL) cursor = &(*cursor)->next;
*cursor = nd;
#else /* Version that avoids use of node** */
int bucket = hash(nd->word);
/* Identify the bucket this node should go into */
if (ht->table[bucket]) {
node * cursor = ht->table[bucket];
while (cursor->next) cursor = cursor->next;
cursor->next = nd;
} else {
ht->table[bucket] = nd;
}
#endif
nd->next = NULL; // Ensure the new node is the last in the list
}
}
/* Free the contents of the given hashtable */
void hashtable_free_contents(hashtable * ht) {
if (ht) {
int i;
for (i=0; i < sizeof(ht->table)/sizeof(ht->table[0]); ++i) {
node * cursor = ht->table[i];
while (cursor != NULL) {
node * next = cursor->next;
free(cursor);
cursor = next;
}
}
}
}
/* Dump the contents of the given hashtable to stdout */
void hashtable_dump(const hashtable * ht) {
if (ht) {
int i;
for (i=0; i < sizeof(ht->table)/sizeof(ht->table[0]); ++i) {
printf("Bucket %d:", i);
node * cursor = ht->table[i];
while (cursor != NULL) {
printf(" %s", cursor->word);
cursor = cursor->next;
}
printf("\n");
}
}
}
int main(int argc, char * argv[]) {
char dictionary[] = {
"apples "
"apricots "
"oranges "
"lemons "
"bananas "
"raspberries "
"carrots "
"tomatoes "
"aubergines "
"limes "
"blueberries "
"plums "
"pears "
"peaches "
"pineapples "
"tangerines "
"kiwis "
"passion_fruit "
"strawberries "
};
hashtable ht;
hashtable_init(&ht);
char * p = dictionary; /* Pointer for traversing the dictionary */
node new_node; /* Temporary node for storing word read from dictionary */
new_node.next = NULL;
int n; /* Number of bytes read from dictionary in sscanf call */
char format[16];
/* If a huge word is in the dictionary, guard against buffer overflow */
snprintf(format, sizeof(format), "%%%ds%%n", sizeof(new_node.word));
while(sscanf(p, format, new_node.word, &n) == 1) {
/* Insert (a copy of the) new node into hashtable */
hashtable_insert_node(&ht, node_create(new_node.word));
/* Move forwards through the dictionary */
p += n;
}
hashtable_dump(&ht);
hashtable_free_contents(&ht);
return 0;
}
Just allocate memory for each node of the hashtable and then dereference them.
i.e.
int i ;
for(i = 0; i < 729; ++i) {
hashtable[i] = malloc(sizeof(node));
hashtable[i]->next = NULL ;
}

How to print a 2D array in C

I've been trying to get my program to print a barchart.
The issue is at the bottom, where I make a 2D array to hold the values and then attempt to
print the array. The problem is that is prints nothing. I've tried to solve it for a few hours with no luck. Any suggestions?
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define DELIM " " /* the delimiter */
#define MAX_CHANGE (10.0/86400.0) /* 10kg/day */
/* seconds in a day is 24 hours * 60 minutes * 60 seconds */
/* return 0 if the passed strings don't math, 1 otherwise */
/* defines the structure of Node */
struct Node{
char * id;
float weight;
int time;
int count;
struct Node * next;
} *head, *p, *t, *last;
/* Constructor which returns a pointer to a new node*/
struct Node *newNode(int *time, char * id, float *w)
{ /*note malloc returns a pointer */
struct Node *r = (struct Node *)malloc( sizeof(struct Node) );
r->time = *time;
r->id = strdup(id); //a duplicate id is made to prevent all the nodes from using the same userID
r->weight = *w;
r->count = 1;
r->next = NULL;
return r;
}
/* prints the list starting with head */
printList(struct Node * head)
{
while(head != NULL)
{
printf("%d %s %f\n",head->time,head->id,head->weight);
head = head->next;
}
return 0;
}
int main() {
char line[1024];
int lasttime = 0;
int success;
int timestamp;
int duration;
char userID[1000] = "";
char *token;
char temp[1000];
float weight;
float lastweight;
float change;
float changePerTime;
head = (struct Node*)malloc(sizeof(struct Node));
head->id = "";
head->weight = 0.0;
head->time = 0;
head->next = NULL;
last = head;
/*FILE * f = fopen("C:\\Users\\Chris\\Documents\\School\\York\\Computer Science\\2031 Software Tools\\Labs\\lab3\\testcases\\01.in","r"); */
/* last points to the last node in the list
head is always the same node
p is used to travers the list
t is a pointer the most recent occurrense of a user record
*/
while (fgets(line,1024,stdin) != NULL) {
userID[0] ='\0'; // resets userID
token = strtok(line, DELIM);
success = sscanf(token,"%d",&timestamp);
if (success < 1 || timestamp == 0)
{
printf("Invalid time\n");
continue;
}
while((token = strtok(NULL,DELIM) ) != NULL && token[0] != '.' && ! isdigit(token[0]) )
{
strcpy(temp,token); //
strcat(temp,DELIM ); // adds space between each token
strcat(userID, temp); // src temp must be a const string, not a pointer
temp[0] = '\0';
}
userID[strlen(userID)-1] = '\0'; //erases the tailing space.
if(strlen(userID) > 179 || !strlen(userID) )
{printf("Illegal userID\n"); continue; }
else if(token == NULL || sscanf(token,"%f", &weight) < 1 || weight < 30.0 || weight > 300.0)
{printf("Illegal weight\n"); continue; }
else if (lasttime >= timestamp)
{printf("Nonmonotonic timestamps\n"); continue; }
else {
/* sets t to last found user record and sets "last" to the last record*/
for(p = head, t = NULL; p != NULL; p = p->next)
{
if(strcmp(userID,p->id) == 0)
{
t=p;
}
last = p; // set last to last p.
}
if(t == NULL)
{
printf("OK newuser\n");
}
else if(t != NULL)
{
/* increments count of id's for this user */
(t->count)++;
duration = timestamp - t->time;
change = weight - t->weight;
changePerTime = change / duration;
if(changePerTime < -MAX_CHANGE || changePerTime > MAX_CHANGE)
printf("Suspiciously large weight change\n");
else
printf("OK\n");
}
/* adds node to end of list */
last->next = newNode(&timestamp,userID,&weight);
last = last->next;
/* adds time to last time */
lasttime = timestamp;
}
}
//fclose(f);
char bc[10][last->count];
int j, i, k, bh;
for(p = head; p != NULL, j <= last->count; p=p->next)
{
if(strcmp(last->id,p->id) == 0)
{
for(i = 11, k=0, bh = (int)(p->weight / 30);i >= 0; i--)
{
if(k < bh)
{
bc[i][j] = '*';
k++;
}
else bc[i][j] = ' ';
}
j++;
}
}
//printf("%c", bc[9][1]);
int m=0, n=0;
for(m < 10; m++;)
{
for(n=0 ;n < last->count; n++)
{
printf("%c",bc[m][n]);
}
printf("%c",'\n');
}
}
Your outer for loop parts are incorrectly placed. Instead of:
for(m < 10; m++;)
You want:
for(m=0;m < 10; m++)
The condition, m<10, is the second part of the for loop, whereas you've mistakenly put it in the initialization part of the loop. Similarly, the increment statement, i++, was in your condition part, so you had no incrementing of the m variable happening.

Resources