So I have files formatted as follows:
2
4 8 4 10 6
9 6 74
The first line is actually the number of rows that the file will have after it. I want to read the files line by line (note there are different number of tokens in each line but all have the format: 1 token and then an unspecified number of pairs of tokens) and do two things for each line:
1) Know how many tokens are in this line.
2) Assign each token to a variable. Using structures similar to:
typedef struct {
unsigned start; //start node of a graph
unsigned end; // end node of a graph
double weight; //weight of the edge going from start to end
} edge ;
typedef struct {
unsigned id; // id of the node
unsigned ne; // number of edges adjacent to node
edge *edges; // array of edge to store adjacent edges of this node
} node;
Some code:
FILE *fin;
unsigned nn;
node *nodes;
fin = fopen ("input.txt", "r");
fscanf(fin,"%u\n", &nn);
nodes = malloc(nn*sizeof(node));
for(i=0; i < nn; i++) { //loop through all the rows
/*grab the row and split in parts, let's say they are part[0], part[1]... */
/*and there are N tokens in the row*/
nodes[i].id=part[0];
nodes[i].ne=(N-1)/2; //number of pairs excluding first element
nodes[i].edges=malloc( (N-1)/2)*sizeof(edge) );
for(j=0; j< (N-1)/2; j++){
nodes[i].edges[j].start=part[0];
nodes[i].edges[j].end=part[2*j+1];
nodes[i].edges[j].weight=part[2*j+2];
}
}
I need to figure out how to do the part comented inside the first for loop to get the number of tokens and each one of them as a simgle token to asign. Any ideas?
EDIT: to make things clear, each line will have first one integer, and then a variable number of pairs. I want to store data as follows:
if the file reads
2
4 8 4 10 6 //(2 pairs)
9 6 74 //(1 pair)
then
nn=2;
node[0].id=4;
node[0].ne=2; //(2 pairs)
node[0].(*edges) //should be a vector of dimension ne=2 containing elements of type edge
node[0].edges[0].start=4; //same as node[0].id
node[0].edges[0].end=8;
node[0].edges[0].weight=4;
node[0].edges[1].start=4; //same as node[0].id
node[0].edges[1].end=10;
node[0].edges[1].weight=6;
node[1].id=9;
node[1].ne=1; //(1 pair)
node[1].(*edges) //should be a vector of dimension ne=1 containing elements of type edge
node[1].edges[0].start=9; //same as node[1].id
node[1].edges[0].end=6;
node[1].edges[0].weight=74;
This code produces the results you described, It initializes your nested struct member edge, and uses strtok. With strtok(), I included the \n as part of the delimiter in addition to a space " \n" to prevent the newline from giving us trouble (see other comments on that below)
Note: you have to free memory where I have indicated, but before you do, preserve the intermediate results (in the structs) or it will be lost.
#include <ansi_c.h>
typedef struct {
unsigned start;
unsigned end;
double weight;
} edge ;
typedef struct {
unsigned id;
unsigned ne;
edge *edges;
} node;
int GetNumPairs(char *buf);
int main(void)
{
FILE *fp;
char *tok;
char lineBuf[260];
int i=0, j=0;
int nn; //number of nodes
char countPairsBuf[260];
fp = fopen("C:\\dev\\play\\numbers.txt", "r");
//get first line of file for nn:
fgets (lineBuf, sizeof(lineBuf), fp);
nn = atoi(lineBuf);
//create array of node with [nn] elements
node n[nn], *pN;
pN = &n[0];
//read rest of lines, (2 through end)
i = -1;
while(fgets (lineBuf, sizeof(lineBuf), fp))
{
i++;
//get number of items in a line
strcpy(countPairsBuf, lineBuf);
pN[i].ne = GetNumPairs(countPairsBuf); //number of edges (pairs)
if(pN[i].ne > 0)
{ //allocate *edges struct element
pN[i].edges = malloc((pN[i].ne)*sizeof(edge));
//get first item in new line as "line token" and "start"
tok = strtok(lineBuf, " \n");
while(tok)
{
pN[i].id = atoi(tok);
//now get rest of pairs
for(j=0;j<pN[i].ne;j++)
{
pN[i].edges[j].start = pN[i].id;
tok = strtok(NULL, " \n");
pN[i].edges[j].end = atoi(tok);
tok = strtok(NULL, " \n");
pN[i].edges[j].weight = atoi(tok);
}
tok = strtok(NULL, " \n"); //should be NULL if file formatted right
}
}
else //pN[i].ne = -1
{
//error, file line did not contain odd number of elements
}
}
//you have to free memory here
//but I will leave that to you
fclose(fp);
}
//GetNumPairs
int GetNumPairs(char *buf)
{
int len = strlen(buf);
int numWords=0, i, cnt=0;
for(i=0;i<len;i++)
{
if ( isalpha ( buf[i] ) ) cnt++;
else if ( ( ispunct ( buf[i] ) ) || ( isspace ( buf[i] ) ) )
{
numWords++;
cnt = 0;
}
}//if odd number of "words", return number of pairs, else error
return (((numWords-1)%2) == 0) ? ((numWords-1)/2) : (-1);
}
Related
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define stock_dir "/Users/myname/prices/"
#define file_list "/Users/myname/trade/trade/nasdaq100_stock_list.txt"
#define look_back_period 3
#define num_stocks 103
#define days_of_data 21
int main()
{
FILE *stocks, *stk;
char stock[11], fullpath[50] = "\0", header[25];
char line_of_data[40];
char *sclose, *svol;
int n = 0, i = 0;
typedef struct daily_data {
char *date;
float close;
int vol;
}data;
sclose = (char*) malloc(20*sizeof(char));
svol = (char*) malloc(20*sizeof(char));
data** day_data = (data**) malloc(num_stocks*sizeof(data*) );
if (day_data == NULL)
{
printf("day_data not allocated\n");
exit(0);
}
for(i = 0; i < num_stocks; i++)
if ((day_data[i] = (data*)malloc(days_of_data*sizeof(data))) == NULL)
{
printf("data[%d] not allocated\n", i);
exit(0);
}
for(i = 0; i < num_stocks; i++)
for(n = 0; n < days_of_data; n++)
if ((day_data[i][n].date = (char*)malloc(20)) == NULL)
{ printf("data[%d][%d] not allocated\n", i,n);
exit(0);
}
/* ... code omitted ... */
if ( (stocks = fopen(file_list, "r") )== NULL)
printf("didn't open file list\n");
i = 0;
while (fgets(stock, sizeof(stock), stocks) != NULL)
{
printf("%s",stock);
strcpy(fullpath,stock_dir);
strcat(fullpath,stock);
fullpath[strcspn(fullpath, "\n")] = 0;
if ( (stk = fopen(fullpath, "r") )== NULL)
printf("didn't open quote list\n");
fgets(header,sizeof(header),stk);
n=0;
while(fgets(line_of_data, sizeof(line_of_data),stk) !=NULL)
{
fgets(line_of_data,sizeof(line_of_data),stk);
day_data[i][n].date = strtok(line_of_data, ",");
sclose = strtok(NULL,",");
day_data[i][n].close = atof(sclose);
svol = strtok(NULL, ",");
day_data[i][n].vol = atoi(svol);;
printf("%s %f %d\n",day_data[i][n].date,day_data[i][n].close,day_data[i][n].vol);
n++;
}
fclose(stk);
i++;
}
for (n = look_back_period - 1; n < (days_of_data - look_back_period); n++)
printf("%d %s %f %d\n",n, day_data[1][n].date, day_data[1][n].close, day_data[1][n].vol);
}
The print statement in the while(fgets(line_of_data, sizeof(line_of_data),stk) !=NULL) loop shows that everything went into the right place. But when I print values outside they're mostly wrong. I'm supposed to add more details but I don't know what else to say. I lose the values in the struct when I leave the loop.
You overwrite the same data again and again.
Take a look at your structure:
typedef struct daily_data {
char *date; ///< a pointer without own storage
float close;
int vol;
}data;
while processing your file you read each line into line_of_data
while(fgets(line_of_data, sizeof(line_of_data),stk) !=NULL)
you tokenize the line_data and assign the pointer to data->date
day_data[i][n].date = strtok(line_of_data, ",");
What tokenize (strtok reference) does is inserting terminators into your input string and returning the pointer to the start of the new part of your input. So no new memory is allocated at this point. the returned pointer points into your input string.
So effectively you assigning the local variable pointer to your data storage structure.
Additionally to this you lose the pointer to your initially allocated memory for the date pointer.
I would suggest you to remove the a priory allocation of date and allocate the required memory at the point you really know the required length or if you are sure, you know the maximum length, then you can just make the date member an array.
So you either have to allocate new memory and copy the tokenized data or if you made date a fixed size array, just copy the tokenized data.
on the first variant it would look like this
char * tok = strtok(line_of_data, ",");
day_data[i][n].date = malloc(strlen(tok)+1);
strcpy(day_data[i][n].date, tok);
(+ remove the pre allocation of the date member)
or the second variant:
change data to
typedef struct daily_data {
char date[20];
float close;
int vol;
}data;
and the processing code looks like this:
char * tok = strtok(line_of_data, ",");
strcpy(day_data[i][n].date, tok);
(+ (of course) remove the pre allocation of the date member)
You also should in any case add error handling if the tokenized string exceeds the max length or the format of the lines does not match the expectation (missing delimiters, wrong/invalid number(formats), ...).
I am trying to build an array of structures with a string and starting address of a linked list of another structure. Several strings from each line of a file is to be filled into this data structure. But whenever I am coming back to the next line, all the variables of the array and LL that I have filled up so far is being changed to the variables in the current line. As a result all the elements of the array as well as the corresponding linked lists are giving the same result in each element of the array. Here is the code.
struct node
{
char* nodedata;
struct node* link;
};
struct motief
{
char* motiefname;
struct node* link;
};
void add_unique_nodes(struct motief*,int,char *);
int unique_motief(struct motief*,char*);
void add_unique_nodes(struct motief* motiefs,int motief_no,char * token)
{
struct node *temp,*r;
r = malloc(sizeof(struct node));
r->nodedata = token;
//for the first node
if(motiefs[motief_no].link == NULL)
{
motiefs[motief_no].link = r;
}
else
{
temp = motiefs[motief_no].link;
while(temp->link != NULL && token != temp->nodedata)
temp = temp->link;
if(token != temp->nodedata)
temp->link = r;
}
r->link = NULL;
}
void main()
{
struct motief motiefs[100];
FILE *fp, *ft;
fp = fopen("dump.txt","r");
ft = fopen("motief_nodes","w");
char line[100] ={0};
char seps[] = ",";
char* token;
int motief_no = 0;
int i,j;//loop variable
//read the database
while(!feof(fp))
{
if( fgets(line, sizeof(line), fp ))
{
if(motief_no == 1)
printf("for start of 2nd step %s\t",motiefs[0].motiefname);//????
printf("for line %d\t",motief_no);
//get the motief from each input line as a token
token = strtok (line, seps);
//store it in motief array
motiefs[motief_no].motiefname = token;
printf("%s\n",motiefs[motief_no].motiefname);
if(motief_no == 1)
printf("for zero %s\n",motiefs[0].motiefname);
motiefs[motief_no].link = NULL;
//get and store all the nodes
while (token != NULL)
{
//get the node
token = strtok (NULL, seps);
if(token != NULL)
add_unique_nodes(motiefs,motief_no,token);
}
if(motief_no == 0)
printf("for end of 1st step %s\n",motiefs[0].motiefname);
motief_no++;
if(motief_no == 2)//break at 2nd loop, at 1
break;
}
I am new to C programming. I cannot find why it is happening. Please help me to find where I am going wrong and why the file is read into the array besides the specified variable for that purpose in my code. Thanks in advance. Here are few lines from the file to be read.
000100110,1,95,89
000100111,1,95,87
000100110,1,95,74
000100110,1,95,51
I am displaying the structure with the following code
struct node* temp;
for(j=0;j<2;j++)
{
printf("turn %d\t",j);
printf("%s\t",motiefs[j].motiefname);
temp = motiefs[j].link;
printf("%s\t",temp->nodedata);
do
{
temp = temp->link;
printf("%s\t",temp->nodedata);
}while(temp->link != NULL);
printf("\n");
}
And the it shows the following overall result
for line 0 000100110
for end of 1st step 000100110
for start of 2nd step 000100111,1,95,87
for line 1 000100111
for zero 000100111
turn 0 000100111 1 95 87
turn 1 000100111 1 95 87
You keep changing the same memory space when you read into 'line'. you need to allocate new memory space each time you want a different array.
Picture 'line' as pointing to a specific chunk of 100 bytes in a row. You keep telling the fgets function to write to that location, and you also keep copying the address of that location into your structs when you assign the 'token' to moteifname.
Then when you change what's at that address of course it's overwriting what the struct points to as well!
You need to choose to allocate the space in each struct instead of having an internal pointer OR you need to dynamically allocate space each iteration using malloc and then free() all the pointers at the end.
https://www.codingunit.com/c-tutorial-the-functions-malloc-and-free
How can I read each individual character from a string that is accessed through an array of pointers? In the below code I currently have generated an array of pointers to strings called, symCodes, in my makeCodes function. I want to read the strings 8 characters at a time, I thought about concatenating each string together, then looping through that char by char but the strings in symCodes could be up to 255 characters each, so I feel like that could possibly be too much all to handle at once. Instead, I thought I could read each character from the strings, character by character.
I've tried scanf or just looping through and always end up with seg faults. At the end of headerEncode(), it's near the bottom. I malloc enough memory for each individual string, I try to loop through the array of pointers and print out each individual character but am ending up with a seg fault.
Any suggestions of a different way to read an array of pointers to strings, character by character, up to n amount of characters is appreciated.
EDIT 1: I've updated the program to no longer output warnings when using the -Wall and -W flags. I'm no longer getting a seg fault(yay!) but I'm still unsure of how to go about my question, how can I read an array of pointers to strings, character by character, up to n amount of characters?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "huffman.h"
#define FAIL 0
#define SUCCESS 1
/* global 1 day arrays that hold chars and their freqs from file */
unsigned long globalFreqs[256] = {0};
unsigned char globalUsedCh[256] = {0};
char globalCodes[256] = {0};
unsigned char globalUniqueSymbols;
unsigned long totalCount = 0;
typedef struct HuffmanTreeNode* HTNode;
struct HuffmanTreeNode* globalSortedLL;
/*
struct has the input letter, the letters frequency, and the left and irght childs
*/
struct HuffmanTreeNode
{
char symbol;
unsigned long freq;
char *code;
struct HuffmanTreeNode *left, *right;
struct HuffmanTreeNode* next;
};
/* does it make sense to have a struct for the entire huffman tree to see its size? */
struct HuffmanTree
{
unsigned size;
};
/*generate new node with given symbol and freq */
struct HuffmanTreeNode* newNode(char symbol, int freq)
{
struct HuffmanTreeNode* newNode = malloc(sizeof(struct HuffmanTreeNode));
newNode->symbol = symbol;
newNode->freq = freq;
newNode->left = newNode->right = NULL;
return newNode;
}
/*current work in progress, i believe this is the way to insert it for a BST
/* will change for HuffmanTreenode once working
/*
*/
struct HuffmanTreeNode* insert(struct HuffmanTreeNode* node, struct HuffmanTreeNode* htnNew)
{
struct HuffmanTreeNode* currentNode = node;
if(currentNode == NULL || compareTwoNodes(htnNew, currentNode))
{
htnNew->next = currentNode;
return htnNew;
}
else
{
while(currentNode->next != NULL && compareTwoNodes(currentNode->next, htnNew))
{
currentNode = currentNode->next;
}
htnNew->next = currentNode->next;
currentNode->next = htnNew;
return node;
}
}
int compareTwoNodes(struct HuffmanTreeNode* a, struct HuffmanTreeNode* b)
{
if(b->freq < a->freq)
{
return 0;
}
if(a->freq == b->freq)
{
if(a->symbol > b->symbol)
return 1;
return 0;
}
if(b->freq > a->freq)
return 1;
}
struct HuffmanTreeNode* popNode(struct HuffmanTreeNode** head)
{
struct HuffmanTreeNode* node = *head;
*head = (*head)->next;
return node;
}
/*convert output to bytes from bits*/
/*use binary fileio to output */
/*put c for individual character byte*/
/*fwrite each individual byte for frequency of symbol(look at fileio slides) */
/*
#function:
#param:
#return:
*/
int listLength(struct HuffmanTreeNode* node)
{
struct HuffmanTreeNode* current = node;
int length = 0;
while(current != NULL)
{
length++;
current = current->next;
}
return length;
}
/*
#function:
#param:
#return:
*/
void printList(struct HuffmanTreeNode* node)
{
struct HuffmanTreeNode* currentNode = node;
while(currentNode != NULL)
{
if(currentNode->symbol <= ' ' || currentNode->symbol > '~')
printf("=%d", currentNode->symbol);
else
printf("%c", currentNode->symbol);
printf("%lu ", currentNode->freq);
currentNode = currentNode->next;
}
printf("\n");
}
/*
#function:
#param:
#return:
*/
void buildSortedList()
{
int i;
for(i = 0; i < 256; i++)
{
if(!globalFreqs[i] == 0)
{
globalSortedLL = insert(globalSortedLL, newNode(i, globalFreqs[i]));
}
}
printf("Sorted freqs: ");
printList(globalSortedLL);
printf("listL: %d\n", listLength(globalSortedLL));
}
/*
#function: isLeaf()
will test to see if the current node is a leaf or not
#param:
#return
*/
int isLeaf(struct HuffmanTreeNode* node)
{
if((node->left == NULL) && (node->right == NULL))
return SUCCESS;
else
return FAIL;
}
/*where I plan to build the actual huffmantree */
/*
#function:
#param:
#return:
*/
struct HuffmanTreeNode* buildHuffmanTree(struct HuffmanTreeNode* node)
{
int top = 0;
struct HuffmanTreeNode *left, *right, *topNode, *huffmanTree;
struct HuffmanTreeNode* head = node;
struct HuffmanTreeNode *newChildNode, *firstNode, *secondNode;
while(head->next != NULL)
{
/*grab first two items from linkedL, and remove two items*/
firstNode = popNode(&head);
secondNode = popNode(&head);
/*combine sums, use higher symbol, create new node*/
newChildNode = newNode(secondNode->symbol, (firstNode->freq + secondNode->freq));
newChildNode->left = firstNode;
newChildNode->right = secondNode;
/*insert new node, decrement total symbols in use */
head = insert(head, newChildNode);
}
return head;
}
void printTable(char *codesArray[])
{
int i;
printf("Symbol\tFreq\tCode\n");
for(i = 0; i < 256; i++)
{
if(globalFreqs[i] != 0)
{
if(i <= ' ' || i > '~')
{
printf("=%d\t%lu\t%s\n", i, globalFreqs[i], codesArray[i]);
}
else
{
printf("%c\t%lu\t%s\n", i, globalFreqs[i], codesArray[i]);
}
}
}
printf("Total chars = %lu\n", totalCount);
}
void makeCodes(
struct HuffmanTreeNode *node, /* Pointer to some tree node */
char *code, /* The *current* code in progress */
char *symCodes[256], /* The array to hold the codes for all the symbols */
int depth) /* How deep in the tree we are (code length) */
{
char *copiedCode;
int i = 0;
if(isLeaf(node))
{
code[depth] = '\0';
symCodes[node->symbol] = code;
return;
}
copiedCode = malloc(255*sizeof(char));
memcpy(copiedCode, code, 255*sizeof(char));
code[depth] = '0';
copiedCode[depth] = '1';
makeCodes(node->left, code, symCodes, depth+1);
makeCodes(node->right, copiedCode, symCodes, depth+1);
}
/*
#function: getFileFreq()
gets the frequencies of each character in the given
file from the command line, this function will also
create two global 1d arrays, one for the currently
used characters in the file, and then one with those
characters frequencies, the two arrays will line up
parallel
#param: FILE* in, FILE* out,
the current file being processed
#return: void
*/
void getFileFreq(FILE* in, FILE* out)
{
unsigned long freqs[256] = {0};
int i, t, fileCh;
while((fileCh = fgetc(in)) != EOF)
{
freqs[fileCh]++;
totalCount++;
}
for(i = 0; i < 256; i++)
{
if(freqs[i] != 0)
{
globalUsedCh[i] = i;
globalFreqs[i] = freqs[i];
if(i <= ' ' || i > '~')
{
globalUniqueSymbols++;
}
else
{
globalUniqueSymbols++;
}
}
}
/* below code until total count is for debugging purposes */
printf("Used Ch: ");
for(t = 0; t < 256; t++)
{
if(globalUsedCh[t] != 0)
{
if(t <= ' ' || t > '~')
{
printf("%d ", globalUsedCh[t]);
}
else
printf("%c ", globalUsedCh[t]);
}
}
printf("\n");
printf("Freq Ch: ");
for(t = 0; t < 256; t++)
{
if(globalFreqs[t] != 0)
{
printf("%lu ", globalFreqs[t]);
}
}
printf("\n");
/* end of code for debugging/vizualazation of arrays*/
printf("Total Count %lu\n", totalCount);
printf("globalArrayLength: %d\n", globalUniqueSymbols);
}
void headerEncode(FILE* in, FILE* out, char *symCodes[256])
{
char c;
int i, ch, t, q, b, z;
char *a;
char *fileIn;
unsigned char *uniqueSymbols;
unsigned char *byteStream;
unsigned char *tooManySym = 0;
unsigned long totalEncodedSym;
*uniqueSymbols = globalUniqueSymbols;
totalEncodedSym = ftell(in);
rewind(in);
fileIn = malloc((totalEncodedSym+1)*sizeof(char));
fread(fileIn, totalEncodedSym, 1, in);
if(globalUniqueSymbols == 256)
{
fwrite(tooManySym, 1, sizeof(char), out);
}
else
{
fwrite(uniqueSymbols, 1, sizeof(uniqueSymbols)-7, out);
}
for(i = 0; i < 256; i++)
{
if(globalFreqs[i] != 0)
{
fwrite(globalUsedCh+i, 1, sizeof(char), out);
fwrite(globalFreqs+i, 8, sizeof(char), out);
}
}
for(t = 0; t < totalEncodedSym; t++)
{
fwrite(symCodes[fileIn[t]], 8, sizeof(char), out);
}
for(q = 0; q < totalEncodedSym; q++)
{
symCodes[q] = malloc(255*sizeof(char));
a = symCodes[q];
while(*a != '\0')
printf("%c\n", *(a++));
}
printf("Total encoded symbols: %lu\n", totalEncodedSym);
printf("%s\n", fileIn);
}
void encodeFile(FILE* in, FILE* out)
{
int top = 0;
int i;
char *code;
char *symCodes[256] = {0};
int depth = 0;
code = malloc(255*sizeof(char));
getFileFreq(in, out);
buildSortedList();
makeCodes(buildHuffmanTree(globalSortedLL), code, symCodes, depth);
printTable(symCodes);
headerEncode(in, out, symCodes);
free(code);
}
/*
void decodeFile(FILE* in, FILE* out)
{
}*/
There are many problems in your code:
[major] function compareTwoNodes does not always return a value. The compiler can detect such problems if instructed to output more warnings.
[major] the member symbol in the HuffmanTreeNode should have type int. Type char is problematic as an index value because it can be signed or unsigned depending on compiler configuration and platform specificities. You assume that char has values from 0 to 255, which is incorrect for most platforms where char actually has a range of -128 .. 127. Use unsigned char or int but cast the char values to unsigned char to ensure proper promotion.
[major] comparison if (globalUniqueSymbols == 256) is always false because globalUniqueSymbols is an unsigned char. The maximum number of possible byte values is indeed 256 for 8-bit bytes, but it does not fit in an unsigned char, make globalUniqueSymbols an int.
[major] *uniqueSymbols = globalUniqueSymbols; in function headerEncode stores globalUniqueSymbols into an uninitialized pointer, definitely undefined behavior, probable segmentation fault.
[major] sizeof(uniqueSymbols) is the size of a pointer, not the size of the array not the size of the type. Instead of hacking it as sizeof(uniqueSymbols)-7, fputc(globalUniqueSymbols, out);
[major] fwrite(tooManySym, 1, sizeof(char), out); is incorrect too, since tooManySym is initialized to 0, ie: it is a NULL pointer. You need a special value to tell that all bytes values are used in the source stream, use 0 for that and write it with fputc(0, out);.
You have nested C style comments before function insert, this is not a bug but error prone and considered bad style.
function newNode should take type unsigned long for freq for consistency.
function buildHuffmanTree has unused local variables: right, top and topNode.
variable i is unused in function makeCodes.
many unused variables in headerEncode: byteStream, c, ch, b...
totalEncodedSym is an unsigned long, use an index of the proper type in the loops where you stop at totalEncodedSym.
unused variables un encodeFile: i, top...
Most of these can be detected by the compiler with the proper warning level: gcc -Wall -W or clang -Weverything...
There are probably also errors in the program logic, but you cannot see these until you fix the major problems above.
I can give my program input files such as the following:
1 0 0 0 2 -1
16 70 -169 -580 75
1 0 4 0 -5
0 -9 3 5 -3
5 -4 3 -2 0
1.0 -3.4 5.4531 -4.2077 1.5092 -0.2030
Each of these lines represents a polynomial. For instance, the first line represents x^6 + 2x^2 - 1
I am trying to read in this file but am not sure how to deal with the tabs and new lines. I am also not sure how to handle the fact that the amount of coefficients and polynomials can change.
Right now I have:
polynomial** readPolyFile(FILE *polyFile){
polynomial *p = NULL;
int size = 1; /* Size to malloc */
polynomial **polynomials = NULL;
polyList = malloc(sizeof(polynomial*) * size); /* Initialize */
if(polyList == NULL){
fprintf(stderr, "%s %n: Could not allocate memory\n", __FILE__, __LINE__);
exit(-99);
}
/* Read all of the data from the file */
do {
}
}
My initial thought is to increment the size each time I need to, but I'm not sure if that's the best way to go about this.
My definition of polynomial is as follows:
typedef struct
{
unsigned int nterms; /* number of terms */
double complex *polyCoef; /* coefficients */
} polynomial;
I would like to return a list of polynomial structs. Any suggestions on how to go about this?
Any suggestions on how to go about this?
Read inputs into a linked list and then form the array when done.
Some quick code, lacking needed error checking, to get you started.
Set up an empty linked-list
typedef struct LL {
polynomial *poly;
struct LL *next;
} LL;
LL head = { NULL, NULL };
LL *p = &head;
Inside the loop, read a line in the a buffer, parse it to a polynomial and append to the LL.
#define N 1000
count = 0;
char buf[N];
/* Read all of the data from the file */
while (fgets(buf, sizeof buf, polyFile)) {
p->next = malloc(sizeof *(p->next));
p = p->next;
// TBD code for OP.
// Hint: degree of polynomial < sizeof buf/2
p->poly = polyList_from_line(buffer);
p->next = NULL;
count++;
}
Allocate for the array
polyList = malloc(sizeof *polyList * count);
p = head.next;
for (i=0; i< count; i++) {
assert(p);
polylist[i] = p->poly;
next = p->next;
free(p);
p = next;
}
return polylist;
Sub problem: More pseudo code to read tab separated data
polynomial *polyList_from_line(char *buffer) {
double complex coef[some factor of N];
count = 0;
char *token = strtok(buffer, "\t");
while (token) {
// parse the token for a complex number
if (sscanf(buffer, tbd_format, tbd_variables) != expected_result)
break;
coef[count++] = ...
token = strtok(tbd_code);
}
// Malloc polynomial using count
// Populate polynomial from coef[]
// return allocation
}
Objective
To create an array of an array of structs, the dimensions based on a file. Then store that into a Linked List.
I am reading from a file formatted like this:
Read a file that is in the form:
name (string) country (string) age (int)
john USA 54
Sam Aus 18
ect
I dont know how many rows and columns the file will have , nor do I know what varible type each column will be
So in theory the first array of struct will contain [NUMBER OF COLUMNS] strucs that will store each variable (using a void pointer and typecasting) along the line( so strucArrayCol[0] = john , structArrayCol[1] = USA ect).
Each of these array of strucs will be stored into another array of strucs which will have [NUMBER OF ROWS] elements so strucArray2Row[0] = strucArrayCol (which contains john , USA and 54) and strucArrayRow[1] will contain another strucArrayCol which contains (sam Aus 18).
So right now I can read the file, and find the number or rows, columns and the variable type of each column.
This is where i start having trouble as im not sure how to go about
1. How to create this array within array ( I know i need to use Malloc)
2.How I would store the variables in the first array of struc, if I
wanted to store age could I just do
void *data = malloc(sizeof(int));
*((int*)data) = TEMP_AGE;
void data being a struc in StrucArrayCol ( in the case of the example if I wanted to store the age of John void* data would be in StrucArrayCol[3] which is inside StucArrayRow[0], as its the 3rd col in the first line)
Sorry if this dosent make sense
Thanks
You can create a linked-list within a linked-list, assuming there is aversion to anything which is not a linked-list! Declare two linked-list node structures, one for rows in the file, and one for columns within each row:
struct column
{
char *buf;
struct column *next;
};
struct row
{
struct column *head;
struct row *next;
};
Read the file one line at a time, add one row node for each line. Each row will have its own link-lists, it will parse the line in to columns.
struct column* column_create(struct column* cursor, char *line)
{
struct column *node = malloc(sizeof(struct column));
node->next = 0;
node->buf = malloc(strlen(line) + 1);
strcpy(node->buf, line);
if (cursor)
cursor->next = node;
return node;
}
struct row* row_create(struct row* cursor, char *line)
{
struct row *node = malloc(sizeof(struct row));
node->next = 0;
node->head = 0;
//parse the line in to columns
struct column *col = 0;
char *token = strtok(line, " \n");
while (token)
{
col = column_create(col, token);
if (!node->head)
node->head = col;
token = strtok(NULL, " \n");
}
if (cursor)
cursor->next = node;
return node;
}
Or you can do this with a 2-dimensional array of text (which would be 3-dimensional array of characters). Or use an array of strings to hold all the lines in the file, then parse each line in to column. From there, you can test each column to see if it is integer or not.
If you don't know the number of lines in the file, use realloc to allocate as much memory is needed during run time. This example reads all the lines in file, and copies it to an array of lines:
int main()
{
FILE *f = fopen("test.txt", "r");
char **lines = 0;
int lines_size = 0;
int lines_capacity = 0;
char buf[1024];
while (fgets(buf, sizeof(buf), f))
{
int len = strlen(buf);
if (!len) continue;
if (lines_size == lines_capacity)
{
lines_capacity += 16;
lines = realloc(lines, lines_capacity * sizeof(char*));
}
lines[lines_size] = malloc(len + 1);
strcpy(lines[lines_size], buf);
lines_size++;
}
int i;
for (i = 0; i < lines_size; i++)
printf("%s", lines[i]);
printf("\n");
for (i = 0; i < lines_size; i++)
free(lines[i]);
free(lines);
return 0;
}
This will work as long as line length in the file never exceeds 1024. Separately, you can parse each line using strtok
void parseline(char *line)
{
char copy[1024];
strcpy(copy, line);
char *token = strtok(copy, " \n");
while (token)
{
printf("[%s], ", token);
token = strtok(NULL, " \n");
}
printf("\n");
}
You need a linked list in a linked list.
Barmak wrote how to get the data. So here is how to get the linked list.
struct sString{
char* str;
void* next_hor;
void* next_ver;
};
struct sInt{
char* Int;
void* next_hor;
void* next_ver;
};
in first column
if ( check type of column)
{for each row
{
generate corresponding struct and link it to previous element (add-function)
}
}
for other columns
{
( check type of column)
{for each row
{
generate corresponding struct and link it to previous element (add-function)
also iterate though linked list and insert the horizontal link
}
}
}
Its very clustered, has tons of overhead and is hard to manage but it should work.
The vertical pointer could also be of the right type as the types don't change in a column.