Here is my struct:
struct Car{
char plateNum[10];
char returnDate[7];
int milage;
float income;
struct Car * next;
};
typedef struct Car Car;
I need to use fwrite and fread to store the value and load back in after. Is there an easy way?
To write a LL to a file
// Be sure to have opened the file in binary mode
Car *x = head;
// Walk the list and write each node.
// No need to write the next field - which happens to be the last one.
// v-----------------v size of data before the `next` field
while (x && fwrite(x, offsetof(Car, next), 1, out_stream) == 1) {
x = x->next;
}
To read records from a file into a LL and return the head node:
#include <stddef.h>
// Be sure to have opened the file in binary mode
Car *ReadCars(FILE *in_stream) {
Car Top;
Top.next = NULL; // code only uses the `next` field of Top
Car *previous = &Top;
Car x;
// While another record was successfully read ...
while (fread(&x, offsetof(Car, next), 1, in_stream) == 1) {
// Fill the next field
x.next = NULL;
// Allocate space and copy
previous->next = malloc(sizeof *(previous->next));
assert(previous->next);
*(previous->next) = x;
// Advance to the next
previous = previous->next;
}
return Top.next;
}
The following was written off the cuff by me and has not been tested, so it might need tweaking. Please also note; for the sake of time, I have not tested the return value of fwrite and fread or checked for read errors. YOU SHOULD DO THIS.
Writing the file
int length = lengthOfList(bar); // Assuming you've already created bar as a linked list of Cars
Car foo[length];
putLinkedListIntoArray(&bar, foo);
FILE* fh = NULL;
if((fh = fopen("filename", "wb")) == NULL) {
// Error and die
}
fwrite(&length, sizeof(int), 1, fh);
fwrite(bar, sizeof(Car), length, fh);
fclose(fh);
Reading the file
FILE* fh = NULL;
if((fh = fopen("filename", "rb")) == NULL) {
// Error and die
}
int length;
fread(&length, sizeof(int), 1, fh);
Car foo[length];
fread(foo, sizeof(Car), length, fh);
fclose(fh);
relinkCarList(foo, length);
Functions
int lengthOfList(Car* start) {
int length;
for(length = 0; start->next != NULL; length++) {
start = start->next;
}
return length;
}
void putLinkedListIntoArray(Car* start, Car* array) {
for(int i = 0; start->next != NULL; i++) {
array[i] = *start;
start = start->next;
}
}
void relinkCarList(Car* array, int length) {
for(int i = 0; i < length; i++) {
if(i < length - 1) {
array[i].next = array[i + 1].next;
}
}
}
Related
Is this possible, what's wrong here!?
I need this to read the list of "items" that belongs inside one node of "Orcamento", and also the list of "decisores".
int lerDadosO(DLLIST3 *orcamentos) {
int nOrcamentos = 0, i = 0;
ORCAMENTO Orcamento;
FILE *ficheiro = fopen("dadosO.bin", "rb");
if(ficheiro != NULL) {
fseek(ficheiro, 0L, SEEK_END);
nOrcamentos = ftell(ficheiro) / sizeof(ORCAMENTO);
rewind(ficheiro);
while (i != nOrcamentos) {
Orcamento.itens = createI();
Orcamento.decisores = createU();
fread(&Orcamento, sizeof(ORCAMENTO), 1, ficheiro);
// viewI(Orcamento.itens, listarItem);
if(insertendO(orcamentos, Orcamento) != 0) {
printf("Ocorreu um Erro!");
return 0;
}
i++;
}
fclose(ficheiro);
}
else {
printf("Não existe nenhum ficheiro binário!");
}
return nOrcamentos;
}
I'm not sure how you have implemented your list system, this may be accomplished by first reading data to a buffer, than transforming that into a "list"
struct record {
int field0
int field1;
};
int main(void) {
// variables
FILE *stream; // reading data
struct record data[length]; // writing data
struct mylisttype *list; // result
...
// read `length` `struct record`s from `stream`
fread(data, sizeof(struct record), length, stream);
listfrombuffer(buffer, list);
...
}
I'm new to C programming, and I'm having some difficulties. I'm trying to re-code to use a linked list to store the structs you read from the file, but I can't understand how to save the text line for line and add it to the linked list.
This is my code:
#include<stdio.h>
#include<stdlib.h>
#include"Cars.h"
void write_to_file() {
FILE* file = NULL;
file = fopen("Cars.dat", "wb");
Car c = { "Toyota", "Civic", "black", 5, 50000 };
size_t ret = fwrite(&c, sizeof c, 1, file);
Car d = { "Toyota1", "Civic1", "Red", 2, 55000 };
ret = fwrite(&d, sizeof d, 1, file);
fclose(file);
}
void print_cars(Car *c, int count) {
FILE* f = fopen("output.txt", "w");
for (int i = 0; i < count; i++) {
fprintf(f, "%s %s %s %d %f\n", c[i].model, c[i].manufacturer, c[i].color, c[i].seatCapacity, c[i].price);
}
fclose(f);
}
void read_from_file() {
Car c;
size_t SIZE = sizeof c;
size_t ret = 1;
FILE* file = NULL;
file = fopen("Cars.dat", "rb");
int count = 0;
do{
ret = fread(&c, sizeof c, 1, file);
if (ret != 1)
break;
count++;
//printf("%s %s %s %d %f\n", c.model, c.manufacturer, c.color, c.seatCapacity, c.price);
}while(!feof(file));
fclose(file);
if (count == 0) {
printf("No cars in the file provided\n");
return;
}
file = fopen("Cars.dat", "rb");
Car* cars_array = NULL;
cars_array = (Car *)malloc(count * SIZE);
ret = fread(cars_array, SIZE*count, 1, file);
//printf("%d\n", ret);
print_cars(cars_array, count);
}
int main()
{
//write_to_file();
read_from_file();
return 0;
}
Struct code:
#ifndef Cars_h
#define Cars_h
typedef struct cars {
char manufacturer[35]; //toyota, honda
char model[35]; //camry, civic
char color[20]; //black, red
int seatCapacity; //4,5
float price; //20k, 25k
}
Car;
#endif
If anyone could give me some pointers on what I need to do next to make it work, I would highly appreciate it. Thank you
You could implement a linked list of 'Car' objects by adding a next pointer to the Car structure. For example:
typedef struct Car {
/* existing fields */
char model[LLL];
char manufacturer[MMM];
char color[CCC];
int seatCapacity;
float price;
struct Car *next; /* new member for linked list */
} Car;
(An assumption is made about Car as source code for Cars.h was not provided.)
You would have to account for this extra field in Cars.dat (where it could be stored with a NULL value assuming that the file has just an array and no notion of a linked list).
When reading, you could malloc space for each Car separately, fread it into the malloc-ed buffer, and update the previous' Car's next pointer to point to the newly loaded Car. In this manner you can build up a simple linked list of Cars.
p.s. I've never heard of a Toyota Civic :)
You can create a new struct as below which includes your Car struct as a field. And a pointer to the next node.
typedef struct {
Car payload;
CarNode* nextNode;
}CarNode
And you don't need to calculate the count of records in the file. Just read one and malloc a CarNode and use the CarNode.payload field as the buffer to hold the content read from the file. Something like below snippet:
CarNode head, tail; // Suppose you are using single linked list.
/*
Initialize the head and tail pointer. At first, they should both point to the first node.
*/
...
/*
Allocate a new node while reading a record from the file.
*/
CarNode *p = (CarNode *)malloc(sizeof(CarNode));
ret = fread(&(p->payload), sizeof(Car), 1, file);
/*
Insert the newly read node into the link list.
*/
tail->nextNode = p;
tail = p;
So I need to write a function that reads all the elements inside a bit file. The point is that I don't know how many elements there could be inside, but I know what type of elements are. So I tried to write this function:
void loadData(Parallelogram **array) {
FILE *data; long size;
//int numberOfElements = 0;
int numberOfObjects = 0;
if ((data = fopen(name, "rb"))!=NULL) {
fseek(data, 0, SEEK_END);
size = ftell(data);
fseek(data, 0, SEEK_SET);
if (size<(long)sizeof(Parallelogram)) {
printf("The file is empty try to open another file maybe");
} else {
Parallelogram *tempArray;
numberOfObjects = size/sizeof(Parallelogram);
tempArray = realloc(*array, numberOfObjects*sizeof(Parallelogram));
if (tempArray==NULL) {
printf("There was an error reallocating memory");
} else { *array = tempArray; }
fread(*array, sizeof(Parallelogram), numberOfObjects, data);
}
}
fclose(data);
}
The elements are struct objects of type Parallelogram, storing a few floats.
The commented out part was me trying another method form another question but not understanding the real mechanism. Anyways when I call the function the array is empty. What am I getting wrong?
EDIT: As requested this is the main function where I call the function loadData()
int main() {
Parallelogram *paraArray = NULL;
loadData(¶Array);
}
EDIT: complete function more or less like the OP's.
You may do something like:
void loadData(Parallelogram **array, size_t * n) {
FILE *data;
if ((data = fopen("file.bin", "rb"))!=NULL) {
Parallelogram buffer[100]; // may be malloc'd
size_t chunk_size = 100;
size_t read_size = 0;
size_t number_of_objects = 0;
Parallelogram *aux = NULL;
*array = NULL;
while ((read_size = fread(buffer, sizeof *buffer, chunk_size, data)) > 0) {
aux = realloc(*array, (number_of_objects + read_size) * sizeof *buffer);
if (aux == NULL) {
// ERROR
free(*array);
// clean, break/exit
}
*array = aux;
memcpy(*array + number_of_objects, buffer, read_size*sizeof *buffer);
number_of_objects += read_size;
}
// check file for errors (ferror()) before exit
fclose(data);
*n = number_of_objects;
}
}
I am currently a student learning data structures, particularly the hashmap. I have been attempting to print my results at the end of my program through a printf command in the main function. Despite the fact that I use these keys in the previous while loop, I can not get the keys to print in my final part
I have tried checking in the insertMap function (seen below) by using a print to indicate whether the key has actually been stored, and It has been, so that doesn't happen to be the error.
int main (int argc, const char * argv[]) {
/*Write this function*/
const char * filename = argv[1];
struct hashMap ht;
char * entWord;
int * oldAt;
int repAt;
int i = 0;
FILE * fp = fopen(filename, "r");
initMap(&ht, 100);
while(!feof(fp)){
entWord = getWord(fp);
/* printf("%s \n", entWord); */
if(!containsKey(&ht,entWord))
insertMap(&ht, entWord, 1);
else{
oldAt = atMap(&ht, entWord);
repAt = *oldAt;
removeKey(&ht, entWord);
insertMap(&ht, entWord, repAt+1);
}
free(entWord);
}
for(i = 0; i < ht.tableSize; i++){
if(ht.table[i] != NULL){
printf("%s: %d \n",ht.table[i]->key,ht.table[i]->value);
}
}
fclose(fp);
return 0;
}
void insertMap (struct hashMap * ht, KeyType k, ValueType v)
{ /*write this*/
int idx = stringHash1(k) % ht->tableSize;
struct hashLink * hlnk;
struct hashLink * plink;
assert(ht);
if(ht->table[idx] == NULL){
hlnk = (struct hashLink *) malloc(sizeof(struct hashLink));
hlnk->value = v;
hlnk->key = k;
hlnk->next = NULL;
ht->table[idx] = hlnk;
ht->count++;
}
else{
plink = ht->table[idx];
hlnk = (struct hashLink *) malloc(sizeof(struct hashLink));
hlnk->value = v;
hlnk->key = k;
hlnk->next = plink->next;
plink->next = hlnk;
ht->count++;
}
}
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.