I'm working to create a rudimentary file system in c++ and am having issues assigning names to files in my directory table. Here is the definition of a directoryEntry struct.
typedef struct{
char name[112];
unsigned int index;
unsigned int size;
unsigned int type;
unsigned int creation;
} directoryEntry;
Here is some code where I create a new blank file.
if(canFit){
for ( int i = 0; i < numClusters; ++i){
if (directoryTable[i].name[0] == 0x00){
//directoryTable[i].name = *newFile;
strcpy(directoryTable[i].name, newFile);
printf("%s %d ", directoryTable[i].name, i);
directoryTable[i].index = location;
directoryTable[i].size = 0;
directoryTable[i].type = 0x0000;
directoryTable[i].creation = time(NULL);
return 0;
}
}
What is happening here is I'm scanning the directory table for entries that contain a null byte as the first character of the filename. This tells me that that particular directory entry is not occupied. Then I use strcpy to assign the newFile (which is declared as a parameter as char newFile[112]).
The problem is the directory name prints properly in the above printf (printf("%s %d ", directoryTable[i].name, i);) but it appears that the data contained in directoryTable[i].name is deleted. The above code is contained in a method called touch. When the code executes I get something like the following:
touch("file1");
file1 0
touch("file2);
file2 0
which means that the value associated to index 0 is temporarily changed to file1, but is then changed back to several null bytes (Which is how it is originally allocated.) So my question is, why doesn't the value of directoryTable[i] stay the same through multiple calls to touch? directoryTable is a global variable so if the value is assigned it shouldn't disappear when out of scope.
It should also be noted that directoryTable is defined as directoryEntry* directoryTable if that has any bearing on my problem.
My professor will not allow us to use most of the standard libraries in C++. Strings, for example, are illegal. So if you are wondering, that is why I'm not using strings.
Thank you for your time.
EDIT:
Here is code where the directoryEntrys that make up the directoryTable are allocated and added to the directoryTable. They are also added to a file but I feel that is irrelevant to this particular question:
fseek(fp, clusterSize * root, SEEK_SET);
for (int i = 0; i < bootRecord[0] / 128 ; ++i){
fseek(fp, clusterSize * root + 128 * i, SEEK_SET);
directoryEntry * newEntry = (directoryEntry *)malloc(sizeof(directoryEntry));
//newEntry->name = (char *)malloc(112);
//memset(newEntry->name, 0x00, 112);
newEntry->size = 0;
newEntry->type = 0;
newEntry->creation = 0x0000;
newEntry->index = 0;
fwrite(newEntry->name, 112, 1, fp);
fwrite(&newEntry->size, sizeof(int), 1, fp);
fwrite(&newEntry->type, sizeof(int), 1, fp);
fwrite(&newEntry->creation, sizeof(int), 1, fp);
fwrite(&newEntry->index, sizeof(int), 1, fp);
directoryTable[i] = *newEntry;
}
You'll need some sort of actual storage defined for your directory table:
#define NUM_FILES 15
DirectoryEntry directoryTable[NUM_FILES]
The pointer you've defined just points to random memory. I'm surprised it doesn't segfault.
Edit
You malloc the DirectoryEntries, but you're not storing them anywhere valid. You have no storage for your pointers, so you're losing them as soon as you assign them to the directoryTable You'll either need to create an array of DirectoryEntry*:
DirectoryEntry* directoryTable[MAX_ENTRIES]
Where you can put your malloc'd pointers or, just create the whole table at runtime:
DirectoryEntry* directoryTable;
int newFS(int size, int clusterSize) {
//Use C++ 'new' instead of malloc
directoryTable = new DirectoryEntry[size / clusterSize];
//Make sure to 'delete directoryTable' at program completion.
}
Related
The code below ask the user to input 10 pairs of artist and titles which can be up to 30 characters long. Everything seems to work fine with allocating the space and printing the data back out. The problem only occurs when I try to free the memory at then end and then only if one of the elements is 4 or more characters long. I suspect I am not allocating the memory correctly but I just can't see it.
// Songs.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
// Experimenting with pointers, structures and dynamic allocation of memory
//
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <iostream>
#include <stdio.h>
struct songInfo
{
char* pArtist; // char pointer for Artist data
char* pTitle; // char pointer for Title data
};
// function prototype declarations
void getSongInfo(struct songInfo *songData, char *Artist, char *Title);
void printSongInfo(songInfo *songData);
int main()
{
struct songInfo songData[10]; // setup array of 10 elements of the structure SongInfo
char sArtist[31];
char sTitle[31];
// prompt user for the artist and title 10 times once for each array element
for (int i = 0; i < 10; i++) {
printf("Artist %i: ", i + 1);
fgets(sArtist, 31, stdin);
strtok(sArtist, "\n"); // trim out return character
printf("Title %i: ", i + 1);
fgets(sTitle, 31, stdin);
strtok(sTitle, "\n"); // trim out return character
getSongInfo(&songData[i], sArtist, sTitle); // allocates the memory and stores the data into the pointer location
}
printSongInfo(songData); // printout the song data stored in the array
// free up the allocated memory space
for (int i = 0; i < 10; ++i) {
free(songData[i].pArtist);
free(songData[i].pTitle);
}
return 0;
}
void getSongInfo(struct songInfo *songData, char *Artist, char *Title) {
songData->pArtist = (char*)malloc(sizeof(Artist) + 1); // Allocate enough memory to hold the string and the null terminator
songData->pTitle = (char*)malloc(sizeof(Title) + 1);
strcpy(songData->pArtist, Artist); // Copy the data into the allocated memory location
strcpy(songData->pTitle, Title);
}
void printSongInfo(songInfo *songData) {
printf("\n%-35s %-35s\n", "Artist", "Title");
printf("%-35s %-35s\n", "-----------------------------------", "-----------------------------------");
for (int i = 0; i < 10; i++) { // iterate through the array of elements
printf("%-35s %-35s\n", songData[i].pArtist, songData[i].pTitle);
}
}
It's not free() call that is invalid, it's malloc.
If you'd print out sizeof(Artist) + 1, you'd likely get either 5 or 9 (depending on your computer architecture). And the same for Title. You check the size of pointer on your machine, which is constant, not the size of array you received.
Undefined Behvaiour means your code may do anything, including "working for now, but will break later at a correct place". You invoke UB by calling strcpy, which tries to copy data into buffer too short to contain the whole string.
You have to pass the size of array to function or calculate it using strlen inside function (and pray that the string is actually null-terminated).
void getSongInfo(struct songInfo *songData, char *Artist, char *Title) {
songData->pArtist = (char*)malloc(strlen(Artist) + 1); // Allocate enough memory to hold the string and the null terminator
songData->pTitle = (char*)malloc(strlen(Title) + 1);
strcpy(songData->pArtist, Artist); // Copy the data into the allocated memory location
strcpy(songData->pTitle, Title);
}
Use std::char_traits::length or strlen. Instead of length of the array, sizeof(Artist) gives you how many bytes a char * pointer occupies.
songData->pArtist =
(char*)malloc(std::char_traits<char>::length(Artist) +
1); // Allocate enough memory to hold the string and the null terminator
songData->pTitle =
(char*)malloc(std::char_traits<char>::length(Title) +
1); // Allocate enough memory to hold the string and the null terminator
Just a side note: using std::string and smart pointers such as std::unique_ptr and std::shared_ptr would save you lots of troubles dealing with memory issues. Overall, using modern c++ will help you write safer code more efficiently.
I'm getting an error in the following code. Visual Studio throws an access violation error when writing to _buf. How can I fix this?
The Sendn function is a socket sending function. It's not the problem, you can ignore it.
It looks like _buf points at 0x00000000
The error message I'm seeing is
0xC0000005: 0x00000000 : access violation
void ?????::?????(int number, string title)
{
int titlesize = sizeof(title);
int bufsize = 4 + 4 + 4 + titlesize;
char *_buf = new char[bufsize];
_buf = { 0 };
// char _buf[bufsize] = { 0 }; (수정 내용)
int commands = 3;
int index = 0;
memcpy(_buf, &commands, sizeof(int));
index += sizeof(int);
memcpy(_buf + index, &number, sizeof(int));
index += sizeof(int);
memcpy(_buf + index, &titlesize, sizeof(int));
index += sizeof(int);
for (int i = 0; i < titlesize; i++)
{
memcpy(_buf + index, &title[i], sizeof(char));
index += sizeof(char);
}
Sendn(_buf, bufsize);
delete[] _buf;
return;
}
char *_buf = new char[bufsize];
_buf = { 0 };
This does not zero-fill the dynamically-allocated array pointed to by _buf. It sets the pointer _buf to be a null pointer. Since _buf is a null pointer, later attempts to dereference it lead to undefined behavior.
There's no need to zero-fill the array pointed to by _buf in this case, so you can simply remove the _buf = { 0 }; line.
Once you've fixed that problem, you also aren't allocating the right amount of memory. sizeof(title) will not give you the number of characters that title holds. It just gives you the static size of a std::string object, which is usually only a pointer and two integers. Use title.size() instead.
You're trying to copy the content of title together with 3 other integer numbers into _buf right? The problem is that sizeof(title) is not the length of the string stored in title. In order to get the length of title, you need to call the member function length on type std::string like this:
auto titlesize = title.length();
The sizeof operator only gives you the size of your std::string object on stack (in comparison, the actual string is stored on heap) and sizeof expressions are always constant expressions. On my computer, sizeof(std::string) is 24 regardless of what the actual string is.
I have attached my code below. I do not see what I am doing wrong. I have a struct that I am trying to serialize into a byte array. I have wrote some some simple code to test it. It all appears to work during runtime when I print out the values of objects, but once I hit return 0 it throws the error:
Run-Time Check Failure #2 - Stack around the variable 'command' was corrupted.
I do not see the issue. I appreciate all help.
namespace CommIO
{
enum Direction {READ, WRITE};
struct CommCommand
{
int command;
Direction dir;
int rwSize;
BYTE* wData;
CommCommand(BYTE* bytes)
{
int offset = 0;
int intsize = sizeof(int);
command = 0;
dir = READ;
rwSize = 0;
memcpy(&command, bytes + offset, intsize);
offset += intsize;
memcpy(&dir, bytes + offset, intsize);
offset += intsize;
memcpy(&rwSize, bytes + offset, intsize);
offset += intsize;
wData = new BYTE[rwSize];
if (dir == WRITE)
{
memcpy(&wData, bytes + offset, rwSize);
}
}
CommCommand() {}
}
int main()
{
CommIO::CommCommand command;
command.command = 0x6AEA6BEB;
command.dir = CommIO::WRITE;
command.rwSize = 128;
command.wData = new BYTE[command.rwSize];
for (int i = 0; i < command.rwSize; i++)
{
command.wData[i] = i;
}
command.print();
CommIO::CommCommand command2(reinterpret_cast<BYTE*>(&command));
command2.print();
cin.get();
return 0;
}
The following points mentioned in comments are most likely the causes of your problem.
You seem to be assuming that the size of Direction is the same as the size of an int. That may indeed be the case, but C++ does not guarantee it.
You also seem to be assuming that the members of CommIO::CommCommand will be laid out in memory without any padding between, which again may happen to be the case, but is not guaranteed.
There are couple of ways to fix the that.
Make sure that you fill up the BYTE array in the calling function with matching objects, or
Simply cast the BYTE* to CommCommand* and access the members directly.
For (1), you can use:
int command = 0x6AEA6BEB;
int dir = CommIO::WRITE;
int rwSize = 128;
totatlSize = rwSize + 3*sizeof(int);
BYTE* data = new BYTE[totalSize];
int offset = 0;
memcpy(data + offset, &comand, sizeof(int));
offset += sizeof(int);
memcpy(data + offset, &dir, sizeof(int));
offset += sizeof(int);
memcpy(data + offset, &rwSize, sizeof(int));
offset += sizeof(int);
for (int i = 0; i < rwSize; i++)
{
data[i + offset] = i;
}
CommIO::CommCommand command2(data);
For (2), you can use:
CommCommand(BYTE* bytes)
{
CommCommand* in = reinterpret_cast<CommCommand*>(bytes);
command = in->command;
dir = in->dir;
rwSize = in->size;
wData = new BYTE[rwSize];
if (dir == WRITE)
{
memcpy(wData, in->wData, rwSize);
}
}
The other error is that you are using
memcpy(&wData, bytes + offset, rwSize);
That is incorrect since you are treating the address of the variable as though it can hold the data. It cannot.
You need to use:
memcpy(wData, bytes + offset, rwSize);
The memory for your struct is laid out without padding, this can be rectified by adding the macro #pragma pack(1) at the start of the struct and #pragma pop() at the end of the struct - check its syntax though.
For your struct to byte conversion, I would use something simple as:
template<typename T, typename IteratorForBytes>
void ConvertToBytes(const T& t, IteratorForBytes bytes, std::size_t pos = 0)
{
std::advance(bytes, pos);
const std::size_t length = sizeof(t);
const uint8_t* temp = reinterpret_cast<const uint8_t*>(&t);
for (std::size_t i = 0; i < length; ++i)
{
(*bytes) = (*temp);
++temp;
++bytes;
}
}
Where T is the is the struct in your case your Command struct and bytes would be the array.
CommIO::CommCommand command;
command.wData = new BYTE[command.rwSize];
ConvertToBytes(command, command.wData);
The resulting array would contain the expected bytes You could specify the offset as well as an extra parameter if you want to start filling your byte array from a particular location
The main problem is here:
memcpy(&wData, bytes + offset, rwSize);
Member wData is a BYTE *, and you seem to mean to copy bytes into the space to which it points. Instead, you are copying data into the memory where the pointer value itself is stored. Therefore, if you copy more bytes than the size of the pointer then you will overrun its bounds and produce undefined behavior. In any case, you are trashing the original pointer value. You probably want this, instead:
memcpy(wData, bytes + offset, rwSize);
Additionally, although the rest of the deserialization code may be right for your actual serialization format, it is not safe to assume that it is right for the byte sequence you present to it in your test program via
CommIO::CommCommand command2(reinterpret_cast<BYTE*>(&command));
As detailed in comments, you are making assumptions about the layout in memory of a CommIO::CommCommand that C++ does not guarantee will hold.
At
memcpy(&wData, bytes + offset, rwSize);
you copy from the location of the wData pointer and to the location of the wData pointer of the new CommCommand. But you want to copy from and to the location that the pointer points to. You need to dereference. You corrupt the heap, because you have only sizeof(BYTE*) space (plus some extra, because heap blocks cannot be arbitrarily small), but you copy rwSize bytes, which is 128 bytes. What you probably meant to write is:
memcpy(wData, *(BYTE*)(bytes + offset), rwSize);
which would take use the pointer stored at bytes + offset, rather than the value of bytes + offset itself.
You also assume that your struct is tightly packed. However, C++ does not guarantee that. Is there a reason why you do not override the default copy constructor rather than write this function?
I've found a very strange issue with both printf (and printf_s), and also std::cout. I'm not sure if it's some short of "glitch" or error in these functions, or if I'm doing something wrong. Since both functions do the same, I'm assuming I'm not doing it the right way.
I have the following structures in my program (By the way, this is a Visual C++ 2010 project):
#pragma pack(push, 1)
typedef struct nameentry
{
char NAME[17];
char EXT[4];
}NAMEENTRY;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct fileentry
{
unsigned int ID;
NAMEENTRY FILENAME;
unsigned int GPFID;
unsigned long long int FPOINTER;
size_t FILESIZE;
}FILEENTRY;
#pragma pack(pop)
Now I have the following portion of code:
NAMEENTRY fname = MCreateNameEntry("LONGFILE.JPG");
FILEENTRY* myfile_ = SearchFileByPkgID(0, fname);
printf("%s", myfile_->FILENAME.NAME);
So what this code is supposed to do is, create an instance of NAMEENTRY with NAME=LONGFILE, and EXT=JPG. Both character arrays are null terminated (last byte is a 0). Then create an instance of FILEENTRY with it's corresponding data from a database I'm developing, then print the name of the file from the FILEENTRY's NAMEENTRY structure.
After running the code, what I get instead of the name of the file, is... garbage. The classic garbage you get when trying to print text from a bad pointer. If I try to print any of the other fields, I also get wrong values.
So obviously, my first thought was that one of my functions were not returning the right value. So I started inspecting the code and, to my surprise, they are actually returning the right values and the structure is filled with the right data. I get the proper values in each field, every character array ends with a 0, etc.
So then I said... "What if I copy the entire block into another instance of FILEENTRY?", and I tried this:
NAMEENTRY fname = MCreateNameEntry("LONGFILE.JPG");
FILEENTRY* myfile_ = SearchFileByPkgID(0, fname);
FILEENTRY dMem;
memcpy(&dMem, myfile_, sizeof(FILEENTRY));
printf("%s", dMem.FILENAME.NAME);
And guess what? It works perfectly fine. I get the name of the file, no garbage. So I'm assuming, either the problem is inside of printf (I also tried std::cout with the same results), or I am doing something wrong when using these functions.
Well, that helps. Seems like the problem was trying to return a pointer to a local variable, as Igor Tandetnik suggested.
So as a workaround, I'm not sure if this is a proper way of handling this, instead of define a local variable, I'm using calloc to allocate a memory block for a FILEENTRY pointer, then fill it and return it. And yes, it seems to work this way.
This is the actual code of the function:
FILEENTRY* SearchFileByPkgID(int ID, NAMEENTRY fname)
{
FILEENTRY* myFile = (FILEENTRY*)calloc(sizeof(FILEENTRY),1);
std::vector<int> results;
unsigned int* dptable = GetDPTableByPkgId(ID);
bool found = false;
for(int x = 0; x < 1024; x++)
{
if(dptable[x] > 0)
{
fseek(PDBFILE, dptable[x], SEEK_SET);
fread(myFile, sizeof(FILEENTRY), 1, PDBFILE);
if(strcmp(myFile->FILENAME.EXT, fname.EXT) == 0)
if(myFile->FILENAME.NAME[0] == fname.NAME[0])
results.push_back(dptable[x]);
}
}
for(int y = 0; y < results.size(); y++)
{
fseek(PDBFILE, results[y], SEEK_SET);
fread(myFile, sizeof(FILEENTRY), 1, PDBFILE);
if(strcmp(myFile->FILENAME.NAME, fname.NAME) == 0)
{
found = true;
break;
}
}
results.clear();
if(found)
return myFile;
else
return 0L;
}
Any more suggestions are wellcome.
I want to write a a mix of int, char, real in void *data.
I am using a file pointer to run through the data block.
Now my question is that since the data type is void, I have to typecast it to int while writing integer and char for writing string.
While typecasting I used the following sample code:
*((int *)data+0) = 14; //writing int
*((int *)data+4) = 5; //writing int, left a space of 4 bytes for int
*((char *)data+8) = 'a'; //writing char
*((char *)data+9) = 'f'; //writing char
But then while reading the values back it didnt give the correct value.
cout<<*((int *)data+0);
cout<<*((int *)data+3);
cout<<*((char *)data+8);
Is the way my code is written correct? I am doubtful about it as data is void.
*((int *)data+4) = 5; // writing 4th int
cout<<*((int *)data+3); // but reading third one
And just in case, ((int *)data+4) points to 4th integer (that is, 16th byte given int size = 4), not to 4th byte. That is, you code overwrites bytes 0-3, then 16-19, then 8th, then 9th. What you probably meant is: *(int *)( (char*)data + X )
Edited to correct mistake pointed out by MSalters
Apart from the typo that others have mentioned (data+3 instead of data+4), you also need to change e.g.
*((int *)data+4)
to
*((int *)data+1)
because adding 4 to an int * doesn't add 4 to the address, it adds 4 * sizeof (int).
If you need to write to an offset that is not a multiple of sizeof(int) (say, 7), you need:
*(int *)((char *)data+7)
For this reason, it might be better to make data a char * to start with, so you can just say
*(int *)(data+7)
Use a class or a struct.
Here, pointer arithmetics is misleading you. When you add 4 to an int * you are adding actually four times sizeof int.
If your data has a constant layout, why don't you just use a struct such as
struct MemoryLayout {
int _first;
int _second;
char _c1;
char _c2;
};
?
You're writing the second one with:
*((int *)data+4) = 5; // offset = 4
and reading it back with:
cout<<*((int *)data+3); // offset = 3
In addition, the (int*) cast is binding to data, not data+4 so that your 4 is scaled up by the size of an int.
If you really want to do this (and a struct is not a possibility due to variances in the data formats), you should cast data to a char*, then add the number of bytes to get the char offset, then cast that to your desired type.
That would be something like:
*((int*)((char*)(data + 0)) = 14; //writing int
*((int*)((char*)(data + 4)) = 5; //writing int
*((char*)data + 8) = 'a'; //writing char
*((char*)data + 9) = 'f'; //writing char
int Data;
//char Data;
//float Data;
FILE *File = fopen("File.txt","wb");
fwrite((char *)&Data,sizeof(Data),1,File);
fclose(File);
File = fopen("File.txt","rb");
fread((char *)&Data,sizeof(Data),1,File);
fclose(File);
...
int DataInt1 = 200;
char DataChar1 = 'N';
FILE *File = fopen("File.txt","wb");
fwrite((char *)&DataInt1,sizeof(DataInt1),1,File);
fwrite((char *)&DataChar1,sizeof(DataChar1),1,File);
fclose(File);
int DataInt2 = 0;
char DataChar2 = 0;
File = fopen("File.txt","rb");
fread((char *)&DataInt2,sizeof(DataInt2),1,File);
fread((char *)&DataChar2,sizeof(DataChar2),1,File);
fclose(File);
printf("%d %d!\n",DataInt2,DataChar2);