Structs for file I/O - c

I was trying to figure out the best way to keep a record of file pointers as well as individual information for each file such as a file path.
My question is, having a folder struct that holds an array of file pointers, and a file struct that holds information for files, how could merge these two concepts so that can I hold an array of file pointers, and store the file path for each of those files?
Header file for a folder struct below:
#ifndef FOLDER_STRUCT_H
#define FOLDER_STRUCT_H
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
struct folder_
{
FILE **files;
size_t current_size;
size_t capacity;
};
typedef struct folder_ folder_t;
folder_t *folder_create(size_t initial_size); //-----------------------Create a folder struct
void folder_destroy(folder_t *folder); //------------------------------Destroy a folder struct
bool folder_insert_file(folder_t *const folder, FILE *const file); //--Insert a file
FILE *folder_get_file(folder_t *const folder, size_t index); //--------Get a file by index
FILE **folder_get_file_list(folder_t *const folder); //----------------Get a list of files
int folder_get_size(folder_t *folder); //------------------------------Get folder size
int folder_get_total_capacity(folder_t *folder); //--------------------Get folder capacity
#endif
Header file for a file struct used to record file information such as a file path:
#ifndef FILE_H
#define FILE_H
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
struct file_
{
FILE *file;
char *file_path;
};
typedef struct file_ file_t;
#endif

The generic approach is if you need both at the same time use another struct, and if you need either use a union probably with a tag field to tell which of the struct it holds. In your case, it sounds like you have 1 folder to n files, so your folder_file_ struct would have an array of files_. If you have more than one folder, then you need an array of folder_file_.
FILE * usually implies an open file handle. Is that really your use case? Opposed to a bunch of paths, and you only open the file as you have to operate on it. Also, why is FILE ** opposed to a FILE *?

Usually is best to let the system manage the file pointers. The file can be reopened outside your struct for example. Or just closed. The struct can get a copy of a FILE* but there is no way to know if it points to the same file as of the moment of creation.
Anyway, sometimes we may need a way to store info for a collection of files.
An EXAMPLE
typedef struct
{
char* name;
FILE* F;
} File;
typedef struct
{
size_t size;
size_t cap; // capacity
size_t inc; // increment
File** info; // data array
} Folder;
Inside File we can store sizes, dates, maybe permissions.
Folder is an array of pointers to File. cap and size are the usual, inc is the size of increment of Folder in files.
A few functions are implemented:
Folder* create(size_t capacity, size_t step);
Folder* destroy(Folder*);
int insert(File*, Folder*);
int show(Folder*, const char*);
int trim(Folder*);
int get_pos(const char* f_name, Folder*);
insert() accepts a File pointer is easy to customize File.
trim() releases all pointers not in use
show() accepts a title, for convenience
get_pos() returns the position of the provided file in the array
destroy() returns NULL to ease in invalidate the pointer in the same line
main for this test
int main(void)
{
const char tst_size = 10;
const char* scan[] = {"File_7533.tst", "File_7500.tst"};
srand(220520);
Folder* tst = create(4, 4);
show(tst, "just created");
char f_name[20] = {0};
for (int i = 0; i < tst_size; i += 1)
{
sprintf(f_name, "File_%04d.tst", 1+rand()%10000);
insert_this(f_name,NULL,tst);
}
sprintf(f_name, "%d files inserted", tst_size);
show(tst, f_name);
trim(tst);
show(tst, "after trim()");
for (int i = 0; i < sizeof(scan) / sizeof(scan[0]);i+=1)
printf( "search por \"%s\" returned %d\n", scan[i],
get_pos(scan[i], tst));
tst = destroy(tst);
return 0;
}
a Folder is created with size 4 and incrementable in groups of 4
10 files are inserted
the contents are listed
search for 2 files
the thing is destroyed
test output
just created
[0/4 files (step = 4)]
insert() size extended to 8
insert() size extended to 12
10 files inserted
[10/12 files (step = 4)]
0 File_2037.tst
1 File_5785.tst
2 File_6602.tst
3 File_7231.tst
4 File_0854.tst
5 File_7102.tst
6 File_7533.tst
7 File_6460.tst
8 File_1717.tst
9 File_1948.tst
trim() new size: 10
after trim()
[10/10 files (step = 4)]
0 File_2037.tst
1 File_5785.tst
2 File_6602.tst
3 File_7231.tst
4 File_0854.tst
5 File_7102.tst
6 File_7533.tst
7 File_6460.tst
8 File_1717.tst
9 File_1948.tst
search for "File_7533.tst" returned 6
search for "File_7500.tst" returned -1
Folder structure destroyed
stuff.h
#ifndef STUFF_H
#define STUFF_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char* name;
FILE* F;
} File;
typedef struct
{
size_t size;
size_t cap; // capacity
size_t inc; // increment
File** info; // data array
} Folder;
Folder* create(size_t capacity, size_t step);
Folder* destroy(Folder*);
int insert(File*, Folder*);
int show(Folder*, const char*);
int trim(Folder*);
int get_pos(const char* f_name, Folder*);
#endif
stuff.c
#include "stuff.h"
Folder* create(size_t capacity, size_t step)
{
Folder* nw = (Folder*)malloc(sizeof(Folder));
if (nw == NULL) return NULL;
nw->size = 0;
nw->cap = capacity;
nw->inc = step;
nw->info = (File**) malloc(nw->cap*sizeof(File*));
for (int i = 0; i < nw->cap; i += 1)
nw->info[i] = NULL;
return nw;
}
Folder* destroy(Folder* f)
{
if (f == NULL) return NULL;
for (int i = 0; i < f->size; i += 1)
{
free(f->info[i]->name);
free(f->info[i]);
}
free(f->info);
free(f);
printf("Folder structure destroyed\n");
return NULL;
}
int insert(File* item, Folder* f)
{
if (f == NULL) return -1;
if (item == NULL) return -2;
if (f->size >= f->cap)
{ // extends folder struct size
size_t new_size = f->cap + f->inc;
File* p = realloc((void*)f->info, new_size*sizeof(File*));
if (p == NULL) return -3; // error extending
f->info = (File**) p;
f->cap = new_size;
printf("insert() size extended to %zd\n", f->cap);
};
// ok, new File then
File* nw = (File*)malloc(sizeof(File));
nw->name = (char*)malloc(1 + strlen(item->name));
strcpy(nw->name, item->name);
nw->F = item->F;
f->info[f->size] = nw;
f->size += 1;
return (int)f->size;
}
int show(Folder* f, const char* msg)
{
if (msg != NULL) printf("%s\n", msg);
printf(
"[%zd/%zd files (step = %zd)\n", f->size, f->cap,
f->inc);
for (int i = 0; i < f->size; i += 1)
{
printf("%3d %s\n", i, f->info[i]->name);
}
printf("\n");
return 0;
}
int trim(Folder* f)
{
if (f == NULL) return -1;
if (f->cap == f->size) return 0; // nothing to do
File* p = realloc((void*)f->info, f->size * sizeof(File*));
if (p == NULL) return -3; // error extending
f->info = (File**) p;
f->cap = f->size;
printf("trim() new size: %zd\n", f->cap);
return 0;
};
int get_pos(const char* f_name, Folder* f)
{
if (f_name == NULL) return -1;
for (int i = 0; i < f->size; i += 1)
if (strcmp(f_name, f->info[i]->name) == 0) return i;
return -1;
}
Note to SO "code reviewers": I do cast all malloc() pointers, as I do not like implicit things and I like them as additional reminders of things to come.

Related

How to read all files in the directory and store them in the pointer in the C language program?

Mingw x86_64 v11.2.0
Windows 10 21H2
My current problem is that this function can normally read files and folders in the directory, but if it is saved in the pointer and printed on the screen, a single file will appear repeatedly.
These are the files in the directory.
.
..
main.c
main.exe
README.md
test.txt
The following is the source code I wrote:
#include "../DeleteCompletely.h"
#include <dirent.h>
#define TotalNumber 4096
#define TotalFileNameLen 4096
typedef struct dirent DIRENT;
typedef struct {
DIR *dir_ptr;
DIRENT *dirent_ptr;
char **pathSet;
size_t number;
} snDIR;
static snDIR *getAllFile(const char *path)
{
snDIR *dirSet = (snDIR *)malloc(sizeof(snDIR));
dirSet->dir_ptr = opendir(path);
size_t loopIndex;
dirSet->pathSet = (char **)malloc(sizeof(char **) * TotalNumber);
if(dirSet->dir_ptr) {
dirSet->number = 0;
loopIndex = 0;
while ((dirSet->dirent_ptr = readdir(dirSet->dir_ptr)) != NULL) {
dirSet->pathSet[loopIndex] = (char *)malloc(TotalFileNameLen);
dirSet->pathSet[loopIndex] = dirSet->dirent_ptr->d_name;
dirSet->number++;
loopIndex++;
}
closedir(dirSet->dir_ptr);
}
return dirSet;
}
int main(int argc, char **argv)
{
snDIR *set = getAllFile(".");
for(size_t x = 0; x < set->number; ++x) {
printf("%s\n", set->pathSet[x]);
}
free(set);
return 0;
}
The problem are these assignments:
dirSet->pathSet[loopIndex] = (char *)malloc(TotalFileNameLen);
dirSet->pathSet[loopIndex] = dirSet->dirent_ptr->d_name;
The first make dirSet->pathSet[loopIndex] point to one location. The second make it point somewhere completely different.
Instead of the second assignment you need to copy the string:
strcpy(dirSet->pathSet[loopIndex], dirSet->dirent_ptr->d_name);
You're also wasting quite a lot of memory by always allocating a large amount or memory. The likelihood of the string being that large are rather small. Instead use the string length as the base size:
dirSet->pathSet[loopIndex] = malloc(strlen(dirSet->dirent_ptr->d_name) + 1);
// +1 for the null terminator

Sorting structures from files

I recently got an assignment to sort members in a struct by last name and if they are the same to sort by first name. What i have so far only reads their name and age from the file but I am not properly grapsing how I would be able to sort it. So far I gathered the data from the file but im at a loss from there. I followed a code I saw but i didnt get a proper grasping of the process so i reverted back to step one.
struct Members{
int id;
char fname[50];
char lname[50];
int age;
}bio;
int main(){
int i=0;
FILE *fptr;
file = fopen("Members Bio.txt", "r");
while ( fscanf(file, "%d%s%s%d", &bio[i].id,bio[i].fname,bio[i].lname,&bio[i].age) != EOF)
{
printf("%d %s %s %d %d\n", bio[i].id,bio[i].fname, bio[i].lname, bio[i].age);
i++;
}
fclose(fptr);
}
Can anyone help me out on this one?
Code goes something like this for your case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Members{
int id;
char fname[50];
char lname[50];
int age;
};
typedef int (*compare_func)(void*, void*);
int struct_cmp(void* s1, void* s2)
{
int l_result = strcmp(((struct Members*) s1)->lname, \
((struct Members*) s2)->lname);
if (l_result < 0)
return 1;
else if (l_result > 0)
return 0;
else
return (strcmp(((struct Members*) s1)->fname, \
((struct Members*) s2)->fname) < 0 ? 1 : 0);
}
void sort(void* arr,long ele_size,long start,long end,compare_func compare)
{
// Generic Recursive Quick Sort Algorithm
if (start < end)
{
/* Partitioning index */
void* x = arr+end*ele_size;
long i = (start - 1);
void* tmp=malloc(ele_size);
for (long j = start; j <= end - 1; j++)
{
if ((*compare)(arr+j*ele_size,x))
{
i++;
// Swap is done by copying memory areas
memcpy(tmp,arr+i*ele_size,ele_size);
memcpy(arr+i*ele_size,arr+j*ele_size,ele_size);
memcpy(arr+j*ele_size,tmp,ele_size);
}
}
memcpy(tmp,arr+(i+1)*ele_size,ele_size);
memcpy(arr+(i+1)*ele_size,arr+end*ele_size,ele_size);
memcpy(arr+end*ele_size,tmp,ele_size);
i= (i + 1);
sort(arr,ele_size,start, i - 1,compare);
sort(arr,ele_size,i + 1, end,compare);
}
}
int main()
{
FILE* fp;
int bio_max = 3;
struct Members bio[bio_max]; // Define bio to be large enough.
/* Open FILE and setup bio matrix */
/* For testing */
bio[0].id = 0;
strcpy(bio[0].fname, "");
strcpy(bio[0].lname, "Apple");
bio[0].age = 0;
bio[1].id = 1;
strcpy(bio[1].fname, "");
strcpy(bio[1].lname, "Cat");
bio[1].age = 1;
bio[2].id = 2;
strcpy(bio[2].fname, "");
strcpy(bio[2].lname, "Bat");
bio[2].age = 2;
/* Sort the structure */
sort(bio, sizeof(struct Members), 0, bio_max - 1, struct_cmp);
/* Print the sorted structure */
for (int i = 0; i < bio_max; i++) {
printf("%d %s %s %d\n", bio[i].id, bio[i].fname, \
bio[i].lname, bio[i].age);
}
}
Output
0 Apple 0
2 Bat 2
1 Cat 1
If the strings are not sorting in the way you want, you can redefine the struct_cmp function. Code is self explanatory, the base logic in the code is pass an array and swap elements using memcpy functions. You cant use simple assignment operator if you want to be generic, so that is why the element size is explicitly passed.
Edit
The code was not handling the condition, if lname are same. I missed it thanks for #4386427 for pointing this out.
I think you should define bio to be an array. And google sort algorithms please. Also recommend you google how to use libc function qsort.

Comparing contents of files for groupings of words

Background:
I am currently working on a project. The main objective is to read files and compare groupings of words. Only user interaction will be to specify group length. My programs are placed into a directory. Inside that directory, there will be multiple textfiles(Up to 30). I use
system("ls /home/..... > inputfile.txt");
system("ls /home/..... > inputfile.txt");
From there, I open the files from inputfile.txt to read for their contents.
Now to the actual question/problem part.
The method I am using for this is a queue because FIFO. (Code "link.c":http://pastebin.com/rLpVGC00
link.c
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "linkedlist.h"
struct linkedList
{
char *data;
int key;
int left;
int right;
int size;
};
LinkedList createLinkedList(int size)
{
LinkedList newLL = malloc(sizeof *newLL);
newLL->data = malloc(sizeof(int) * (size+1));
newLL->size = size;
newLL->left = 0;
newLL->right = 0;
return newLL;
}
bool isFull(LinkedList LL)
{
return abs(abs(LL->left)- abs(LL->right)) == LL->size;
}
void insertFront(LinkedList LL, char *newInfo)
{
if(isFull(LL))
{
printf("FULL");
exit(1);
}
LL->data[((--(LL->left) % LL->size) + LL->size) % LL->size] = newInfo;
}
bool isEmpty(LinkedList LL)
{
return LL->left == LL->right;
}
const char * removeEnd(LinkedList LL)
{
if(isEmpty(LL))
{
return "EMPTY";
//exit(1);
}
return LL->data[((--(LL->right) % LL->size) + LL->size) % LL->size];
}
I get two warnings when I compile with link.c and my main (Start11.c)
link.c: In function ‘insertFront’:
link.c:39:64: warning: assignment makes integer from pointer without a cast [enabled by default]
LL->data[((--(LL->left) % LL->size) + LL->size) % LL->size] = newInfo;
^
link.c: In function ‘removeEnd’:
link.c:54:5: warning: return makes pointer from integer without a cast [enabled by default]
return LL->data[((--(LL->right) % LL->size) + LL->size) % LL->size];
^
FULL start11.c code: http://pastebin.com/eskn5yxm .
From bulk of read() function that I have questions about:
fp = fopen(filename, "r");
//We want two word or three word or four word PHRASES
for (i = 0; fgets(name, 100, fp) != NULL && i < 31; i++)
{
char *token = NULL; //setting to null before using it to strtok
token = strtok(name, ":");
strtok(token, "\n");//Getting rid of that dirty \n that I hate
strcat(fnames[i], token);
char location[350];
//Copying it back to a static array to avoid erros with fopen()
strcpy(location, fnames[i]);
//Opening the files for their contents
fpp = fopen(location, "r");
printf("\nFile %d:[%s] \n", i+1, fnames[i]);
char* stringArray[400];
//Reading the actual contents
int y;
for(j = 0; fgets(info,1600,fpp) != NULL && j < 1600; j++)
{
for( char *token2 = strtok(info," "); token2 != NULL; token2 = strtok(NULL, " ") )
{
puts(token2);
++y;
stringArray[y] = strdup(token2);
insertFront(index[i],stringArray[y]);
}
}
}
//Comparisons
char take[20010],take2[200100], take3[200100],take4[200100];
int x,z;
int count, count2;
int groupV,groupV2;
for(x = 0; x < 10000; ++x)
{
if(removeEnd(index[0])!= "EMPTY")
{
take[x] = removeEnd(index[0]);
}
if(removeEnd(index[1])!= "EMPTY")
{
take2[x] = removeEnd(index[1]);
}
if(removeEnd(index[2])!= "EMPTY")
{
take3[x] = removeEnd(index[2]);
}
}
for(z = 0; z < 10; z++)
{
if(take[z] == take2[z])
{
printf("File 1 and File 2 are similar\n");
++count;
if(count == groupL)
{
++groupV;
}
}
if(take[z] == take3[z])
{
printf("File 1 and File 3 are similar\n");
++count2;
if(count == groupL)
{
++groupV2;
}
}
}
Are those two warnings before the reason why when I try to compare the files it'll not be correct? (Yes I realize I "hardcoded" the comparisons. That is just temporary till I get some of this down...)
I'll post header files as a comment. Won't let me post more than two links.
Additional notes:
removeEnd() returns "EMPTY" if there is if there is nothing left to remove.
insertFront() is a void function.
Before I created this account so I can post, I read a previous question regarding strttok and how if I want to insert something I have to strdup() it.
I have not added my free functions to my read() function. I will do that last too.
start.h (pastebin.com/NTnEAPYE)
#ifndef START_H
#define START_H
#include "linkedlist.h"
void read(LinkedList LL,char* filename, int lineL);
#endif
linkedlist.h (pastebin.com/ykzbnCTV)
#include <stdlib.h>
#include <stdio.h>
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
typedef int bool;
typedef struct linkedList *LinkedList;
LinkedList createLinkedList(int size);
bool isFull(LinkedList LL);
void insertFront(LinkedList LL, char *newInfo);
const char * removeEnd(LinkedList LL);
bool isEmpty(LinkedList LL);
#endif
The main problem is around the removeEnd (resp. insertFrom) function:
const char * removeEnd(LinkedList LL)
{
if (...)
return "EMPTY";
else
return LL->data[xxx];
you return a const char * in the first return but a char in the second return, hence the warning, which is a serious one.
And when you compare return value to "EMPTY" in the caller, it's just wrong: you should use strcmp instead of comparing arrays which may be the same depending on compilers which group same strings in the same location, but only by chance (and not portable!)

Want to fill Structure for Metadata

Here i have one directory which has number of files.
I want to fill this files all information in one structure.
I have two structures which are following.
struct files {
char *file_name;
int file_size;
};
typedef struct file_header {
int file_count;
struct files file[variable as per number of files];
} metadata;
i want to make one header which contains all information regarding these files.
like if i have 3 files than i want to make this structure like this in file_count = 3 and how can i allocate second variable value? and want to store file name and file size as per file.
i want file structure like this
file_count = 3
file[0].file_name = "a.txt"
file[0].file_size = 1024
file[1].file_name = "b.txt"
file[1].file_size = 818
file[2].file_name = "c.txt"
file[2].file_size = 452
I have all logic about file name and file size but how can i fill these things in this structure.?
Code :
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
char path[1024] = "/home/test/main/Integration/testing/package_DIR";
//int count = 5;
struct files {
char *file_name;
int file_size;
};
typedef struct file_header {
int file_count;
struct files file[5];
} metadata;
metadata *create_header();
int main() {
FILE *file = fopen("/home/test/main/Integration/testing/file.txt", "w");
metadata *header;
header = create_header();
if(header != NULL)
{
printf("size of Header is %d\n",sizeof(metadata));
}
if (file != NULL) {
if (fwrite(&header, sizeof(metadata), 1, file) < 1) {
puts("short count on fwrite");
}
fclose(file);
}
file = fopen("/home/test/main/Integration/testing/file.txt", "rb");
if (file != NULL) {
metadata header = { 0 };
if (fread(&header, sizeof(header), 1, file) < 1) {
puts("short count on fread");
}
fclose(file);
printf("File Name = %s\n", header.file[0].file_name);
printf("File count = %d\n", header.file_count);
printf("File Size = %d\n", header.file[0].file_size);
}
return 0;
}
metadata *create_header()
{
int file_count = 0;
DIR * dirp;
struct dirent * entry;
dirp = opendir(path);
metadata *header = (metadata *)malloc(sizeof(metadata));
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_type == DT_REG) { /* If the entry is a regular file */
header->file[file_count].file_name = (char *)malloc(sizeof(char)*strlen(entry->d_name));
strcpy(header->file[file_count].file_name,entry->d_name);
//Put static but i have logic for this i will apply later.
header->file[file_count].file_size = 10;
file_count++;
}
}
header->file_count = file_count;
closedir(dirp);
//printf("File Count : %d\n", file_count);
return header;
}
output :
size of Header is 88
ile Name = �~8
File count = 29205120
File Size = -586425488
Its shows different output. so whats problem here?
Among other things, you are using sizeof on a pointer variable, but seem to think that gives you the size of the object being pointed to. It doesn't. To do that, use the asterisk operator to make the expression have the type that the pointer points at:
printf("size of Header is %d\n", sizeof *metadata);
As a side note, notice that sizeof is not a function, so you don't need parenthesis. When you do see parenthesis, that's when they're part of the expression (a cast).
You are not leaving enough room for the null-terminator:
header->file[file_count].file_name = (char *)malloc(sizeof(char)*strlen(entry->d_name));

C Programming - Malloc Structs and undefined arrays

I am writing a program in C and I am trying to create these structs.
I have three of them:
the first consisting of 2 ints and 2 chars,
the second consisting of an int and an undefined array of pointers to the first one,
and a third which contains 4 longs and 2 ints along with an undefined array of pointers to the second.
I am having trouble I believe with memory allocation for these structs when instantiated. Does anyone know what I am doing wrong (code below). Cache_Simulator is the main class and uses the others. Any help appreciated.
Directory_block.c
#include <stdio.h>
#include <stdlib.h>
#include "Directory_Block.h"
/* Created September, 15th, 2010;
*
* Author: TJ, Cory
*/
char containsData(directory_block* checkMe){
return checkMe->valid;
}
void setValidOn(directory_block* checkMe){
checkMe->valid = 1;
}
void setValidOff(directory_block* checkMe){
checkMe->valid = 0;
}
char isOlder(directory_block* checkMe, int currentOldest){
if(currentOldest < checkMe->LRU){
return 1;
}
else{
return 0;
}
}
void setTag(directory_block* setMe, int tag){
setMe->tag = tag;
}
char matchesTag(directory_block* checkMe, int theirTag){
if(checkMe->tag == theirTag){
return 1;
}
else{
return 0;
}
}
void incrementLRU(directory_block* incrementMe){
incrementMe->LRU++;
}
void setLRU(directory_block* editMe, int LRUVal){
editMe->LRU = LRUVal;
}
cache_set* createSet(int setNumber,int numberOfBlocks,int printDetails){
cache_set* newSet = malloc(sizeof(cache_set) + sizeof(directory_block)*numberOfBlocks);
newSet->setNumber = setNumber;
printf("Making Set %d\n",newSet->setNumber);
int i = 0;
for(; i < numberOfBlocks;i++)
{
printf("\tMaking Block #%d ",i);
if((i%4)==0&&i!=0)
{
printf("\n");
}
directory_block* block = malloc(sizeof(directory_block));
newSet->blocks[i] = block;
setValidOff(newSet->blocks[i]);
setTag(newSet->blocks[i],setNumber);
setLRU(newSet->blocks[i],-1);
if(printDetails == 1)
{
printf("\tAddress %d\n",(int)newSet->blocks[i]);
printf("\t\tValid=%d\n\t\tLRU=%d\n\t\tTag=%d\n",newSet->blocks[i]->valid
,newSet->blocks[i]->LRU,newSet->blocks[i]->tag);
}
}
printf("\n");
return newSet;
}
Directory_block.h
#ifndef DIRECTORY_BLOCK_H_
#define DIRECTORY_BLOCK_H_
#include "Directory_Block.h"
struct directory_block;
struct set;
struct cache;
typedef struct{
int tag;
int LRU;
char valid;
char offset;
}directory_block;
typedef struct{
int setNumber;
directory_block* blocks[];
}cache_set;
typedef struct{
int numberOfSets;
int linesPerSet;
long hits;
long misses;
long unknownAccesses;
long flushes;
cache_set* sets[];
}cache;
/*
* params: checkMe - the line of the cache that we are checking
* return: true = valid == 1; false valid == 0
*/
char containsData(directory_block* checkMe);
/*
* functions: to set the valid bit to 1
*/
void setValidOn(directory_block* checkMe);
/*
* functions: to set the valid bit to 0
*/
void setValidOff(directory_block* checkMe);
/*
* params: currentOldest - the current oldest in directory_block*
* return: the oldest current directory_block*
*/
char isOlder(directory_block* checkMe, int currentOldest);
/*
* params: theirTag - the tag that is in the directory_block*
* return: 0 if false; 1 is true
*/
char matchesTag(directory_block* checkMe, int theirTag);
/*
* function: increments the value of the LRU in the block
*/
void incrementLRU(directory_block* incrementMe);
void setTag(directory_block* setMe, int tag);
/*
* param: LRUVal - value to set to LRU to (negative means hasn't been used)
*/
void setLRU(directory_block* editMe,int LRUVal);
/*
* param: numberOfBlocks number of blocks per set
* creates a set and instantiates all directory blocks;
* param: setNumber number of this set in the cache
*/
cache_set* createSet(int setNumber,int numberOfBlocks,int details);
#endif /* DIRECTORY_BLOCK_H_ */
Cache.c
#include "Directory_Block.h"
#include <stdio.h>
#include <stdlib.h>
directory_block* findLRU(cache* checkMe,int index){
int age;
age = 0;
int i = 0;
int oldest = 0;
for(; i < checkMe->numberOfSets;i++)
{
if(isOlder(checkMe->sets[i]->blocks[index],age) == 1)
{
oldest = i;
age = checkMe->sets[i]->blocks[index]->LRU;
}
}
return checkMe->sets[i]->blocks[i];
}
int readInAddress(cache checkMe,char fileName[]){
return 0;
}
cache *makeCache(int numberOfLines,int numberOfSets,int details){
cache* returnMe = (cache*)malloc(sizeof(cache) + sizeof(int)*numberOfSets);
returnMe->numberOfSets = numberOfSets;
returnMe->linesPerSet = numberOfLines;
printf("Making Cache\n");
int i=1;
for(; i < returnMe->numberOfSets;i++){
returnMe->sets[i] = createSet(i,returnMe->linesPerSet,details);
}
return returnMe;
}
void writeToCache(cache *addToMe,int address,int tag,int offset)
{
directory_block* LRUblock = findLRU(addToMe,address);
LRUblock->LRU = 0;
LRUblock->tag = tag;
LRUblock->valid = 1;
LRUblock->offset = offset;
}
char processAddress(cache checkMe,int address){
return 0;
}
void reportCacheStatus(cache *reportMe){
int i = 0;
int j = 0;
for(;i < reportMe->numberOfSets;i++)
{
printf("Set #%d\n",i);
for(j=0;j < reportMe->linesPerSet;j++)
{
printf("\tBlock #%d - Tag=%d Valid=%d LRU=%d Offset=%d\n",j,reportMe->sets[i]->blocks[j]->tag
,reportMe->sets[i]->blocks[j]->valid,reportMe->sets[i]->blocks[j]->LRU
,reportMe->sets[i]->blocks[j]->offset);
}
}
}
Cache.h
#include "Set.h"
#ifndef CACHE_H_
#define CACHE_H_
/*
* params: checkMe - cache which that we will look for LRU at
* index - line index which we will check for LRU in all sets
* return: setIndex - of the LRU block
* function - iterates through sets and compares LRU value of directory_block at given
* index for each set.
*
*/
int findLRU(cache checkMe,int index);
/*
* params: char [] - Name of File to read
* return address struct contains access type and parsed address
*/
int readInAddress(cache checkMe,char[]);
/*
*params: int cacheSize total bytes in cache, int linesPerSet number of blocks per set
*params: int lineSize number of bytes per line
* return int [] pointer with # of fields
* (DEFINE FIELDS)
*/
cache* makeCache(int numberOfLines,int numberOfSets,int details);
/*
* params: int address - perform cpu call for that address and see if there is a
* hit or miss or unknown access type - Update stats
*/
char processAddress(cache checkMe,int address);
void writeToCache(cache *addToMe,int address);
/*
*Prints out display of information
*For passes cache
*Ex.
* INSERT EXAMPLE LINE
*/
void reportCacheStatus(cache* reportMe,int numberOfSets,int blocksPerSet);
#endif /* CACHE_H_ */
Cache_simulator.c
#include <stdio.h>
#include <stdlib.h>
#include "fileParser.h"
#include "Directory_Block.h"
#include "Cache.h"
void setupCache(int details);
void performTrace(void);
void report(void);
int main(void)
{
printf("The Cache Simulator:\n\tJonathan Katon\n\tCory Brett\n\tThomas Pavlu\n");
setupCache(1);
//performTrace();
report();
return 0;
}
void setupCache(int details)
{
int numberOfLines = 1024/1;
int numberOfSets = numberOfLines/4;
numberOfLines = numberOfLines/numberOfSets;
printf("Number of Sets %d \nNumber of Lines Per Set %d\n",numberOfSets,numberOfLines);
printf("Cache Size %d,Cache_Set Size %d,Directory_block Size %d",sizeof(cache),sizeof(cache_set),sizeof(directory_block));
cache *instructionCache = makeCache(numberOfLines,numberOfSets,details);
//writeToCache(instructionCache,0);
reportCacheStatus(instructionCache,numberOfSets,numberOfLines);
}
void performTrace(void)
{
FILE* trace;
trace = fopen("trace.txt","r");
readNextMemoryAccess(trace);
}
void report(void)
{ // T.B.D
}
From an 'answer' by the OP about the question:
This was my attempt to try and fix a problem I was having with the memory at least i think I was. When I do a sizeof(cache_set) only it only returns a size large enough for everything but the array of pointers. This makes sense because the array isn't finite my question is how do I get around this issue? Any suggestions. Oh, and by the way, thanks for taking at look at this.
in Directory_block.c
cache_set* newSet = malloc(sizeof(cache_set) + sizeof(directory_block)*numberOfBlocks);
newSet is a pointer with space for:
1 cache_set: ok
numberOfBlocks directory_blocks: huh?
This is wrong: cache_sets do not have directory_blocks in them; they have pointers to directory_blocks
typedef struct{
int setNumber;
directory_block* blocks[];
}cache_set;
I'd pay great attention to your type structure. Do you really need an array of pointers to directory_blocks inside cache_sets? If you do, the typedef is ok; if you don't, it's (probably) the code that's ok ... but, anyway, ... the structure and the malloc don't match.
Edit use the flexible array member
Suppose we have a struct with a flexible array member
struct Example {
int value;
double fam[]; /* fam is the flexible array, of doubles */
};
and now we want to use a variable of type struct Example with space for 100 doubles:
struct Example *example;
example = malloc(sizeof *example + 100 * sizeof *example->fam);
if (example) {
/* use example, eg: */
example->fam[42] = 3.14159265;
/* and remember to free the allocated object when done */
free(example);
}

Resources