0

I was tasked with creating a random access/ binary list and allowing the program to erase a target record (struct) from it using the windows.h library and it's HANDLE functions. I'v written the following code in an attempt to truncate files, and while erasing something right at the end of a file seems to work, the section handling files in the middle seems to be making trouble, and im stumped.

void erase_record(FILE *file, stct buffer, char *target)
{
HANDLE h;
int jump=0;
int mark;
stct s;
file = fopen("list.txt","rb+");
s.artist = (char*)malloc(20*(sizeof(char)));
s.name = (char*)malloc(20*(sizeof(char)));
while(1)
{
    jump++;
    fread(&buffer,sizeof(buffer),1,file);
    if(!strcmp(target,buffer.name)) // did we find a match? 
    {
        jump--;
        fread(&buffer,sizeof(buffer),1,file); // then check one more time.
        if(feof(file)) // is the match right before the eof?
        {
            fclose(file);
            h=CreateFile(L"list.txt",GENERIC_WRITE | GENERIC_READ,0,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
            SetFilePointer(h,(jump)*sizeof(buffer),NULL,FILE_BEGIN); // truncate from last
            SetEndOfFile(h);
            CloseHandle(h);
            break;
        }
        else // is it in middle of the file?
        {
            mark = jump; // we mark the struct we wanted to delete
            while(1)
            {
                s.shelf = buffer.shelf;
                s.artist = buffer.artist;
                s.name = buffer.name;
                jump++;
                fread(&buffer,sizeof(buffer),1,file); // find the end of the file first
                if(feof(file))// when we DO find the end..
                {
                    break;
                }
            }
            fclose(file);
            h=CreateFile(L"list.txt",GENERIC_WRITE | GENERIC_READ,0,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
            SetFilePointer(h,(jump)*sizeof(buffer),NULL,FILE_BEGIN); //deleting it!
            SetEndOfFile(h);
            CloseHandle(h);
            file = fopen("list.txt","rb+");
            fseek(file,mark*sizeof(buffer),SEEK_SET); // we erase the marked struct
            fwrite(&s,sizeof(s),1,file);
            break;
        }
    }
}

}

Can anyone share any insight on what went wrong?

4

2 回答 2

1

The problem will be related to something below I think. The penny dropped when you said the following:

Well, i checked with ferror() but it returned 0. The program just crashes after i try running the section i mentioned and after running through a debug tool i get "Unhandled exception at 0x577514cf (msvcr100d.dll) in Project 5.exe: 0xC0000005: Access violation reading location 0xcdcdcdcd."

The value 0xcdcdcdcd is

"...a debugging value that comes from the bowels of the C runtime library. When you allocate a block of memory in a debug build, it's initialized to this spurious value in the hope of catching bugs. 0xCDCDCDCD is non-NULL and is never a valid memory pointer..." (http://www.microsoft.com/msj/1198/c/c1198.aspx).

This implies therefore that something has failed to allocate memory.

First thing I'd do is check the malloc() statements do not return NULL.

Next, check the return value of fopen() is not NULL.

Next thing is the following lines...

s.artist = buffer.artist;
s.name = buffer.name;

They are introducing a memory leak. You are not copying the string here, you are copying a pointer. Thus the previous memory you malloc()'ed for artist and name is now lost, you'll never be able to free() it. I think you probably meant to use strcpy() to copy the string from buffer into s.name, for example?

Also, are you writing the pointers to a file? If you read back buffer.name and it is a pointer (I think it must be because you treat it as such) then you're reading back any old address that was valid when you created the file, but in this instance of your program could be completely invalid! Trying to then dereference that pointer will then cause you headaches!

I would suggest that when you write the structure to the file you do NOT write the pointers s.name and s.artist but write the actual strings to the file. Then read back the strings from the file, then create pointers for them.

fwrite(&s,sizeof(s),1,file); // OOPS! You wrote pointer values to a file. 
// These pointers will be invalid addresses in the next program instance!

Instead do something like..

fwrite(all non pointer members of struct)
fwrite(&s.label, LABEL_LEN, 1, file); // Note, include the string null-terminator
fwrite(&s.name, NAME_LEN, 1, file);   // Note, include the string null-terminator

Then when you read, read back the label and name as actual strings...

fread(all non pointer members of struct)
fread(&stringBuffer, LABEL_LEN, 1, file);
s.label = strdup(stringBuffer);
fread(&stringBuffer, NAME_LEN, 1, file);
s.name= strdup(stringBuffer);

Then later on remember to free() s.name and s.label as strdup() has created a copy which you are responsible to dispose of.

于 2013-05-25T09:32:06.660 回答
0

I'v noodled it out. Apparently, i forgot something very important. That was to close (as in fclose()) the file. This one is always said to cause problems, and this is an example.

于 2013-05-25T09:26:02.797 回答