Malloc размера на файловия буфер на базата на съществуващ файл

В моя проект трябва да копирам споделения файл в директория, наречена share. Идеята ми е да копирам съдържанието на този файл с помощта на fgets и fputs:

FILE *fp;
int size;
char *fileBuff

fseek(fp,0,SEEK_END );
size=ftell(fp);
printf("Size of %s: %d bytes.\n",path,size); // print correct size 
fileBuff=malloc(size); // mallocate the file buffer
printf("\nsize of file buffer is %d",sizeof(fileBuff)); //always print 4!!
while(!feof(fp)){
    fgets(fileBuff,size,fp); // put into file buffer

}
printf("\nsize of file buffer is %d",sizeof(fileBuff)); // also print 4!!

Въпреки това, файловият буфер не може да бъде неправилно разпределен, размерът на този файлов буфер винаги е 4. какво се случва?

актуализация: изглежда има някакво недоразумение. sizeof() само за да проверя дали има нещо, съхранено във файловия буфер. Опитвам strlen(fileBuff) и винаги ми дава 1.


person panda    schedule 13.04.2012    source източник
comment
По-добре да използвате fstat, за да намерите размера на файла, вместо да търсите до края и т.н.   -  person Ed Heal    schedule 13.04.2012


Отговори (5)


Това е грешно: sizeof(fileBuff). Това ще бъде размерът на показалеца, който е 4 във вашата система.

Не можете да използвате sizeof за "извличане" на размера на блок памет, върнат от malloc(). Не можете да използвате нищо, за да извлечете този размер, това просто не е възможно в (стандартен) C. Трябва да използвате стойността size, т.е. аргумента за malloc().

Освен това ftell() връща long, а не int и както malloc(), така и различните I/O извиквания могат да се провалят, което трябва да вземете предвид.

Според мен не е добра идея да се използва буфер с размера на файла, за да се направи просто копие; много по-добре е да използвате "разумен" буфер (чийто точен оптимален размер зависи от много фактори) и след това да правите повтарящи се двойки четене-запис в цикъл, докато не преминете през целия файл.

АКТУАЛИЗАЦИЯ Допълнителни точки относно вашия код:

  1. Говорите за използване на strlen(), но кодът също показва sizeof след fread().
  2. Говорите за използване на sizeof за "проверка" дали има нещо в буфера, това не е възможно; всеки израз с sizeof винаги се оценява по време на компилиране1, не може да се използва за проверка на динамични неща като тези. И отново не можете да го използвате, за да изчислите размера на блок памет, върнат от malloc().
  3. Използването на strlen() в буфер, съдържащ файлови данни, работи надеждно само ако файлът е двоичен и съдържа '\0' в последната си позиция, в противен случай ще имате незавършен низ и strlen() може да извика недефинирано поведение.
  4. Както казах, трябва да проверите дали malloc() връща NULL, което ще направи, ако не успее да разпредели искания блок памет.

1 С изключение на гъвкави масиви в C99, но нека игнорираме това .

person unwind    schedule 13.04.2012
comment
много ви благодаря, но защо мога да преместя файловия буфер? само заради типа данни? програмата не съобщава за грешка, но няма нищо поставено във файловия буфер. Това просто не може да бъде нарушено - person panda; 13.04.2012

99 разработчици сега ще отговорят, че приемате размера на показалец. Дори не трябва да гледам кода.

person Martin James    schedule 13.04.2012
comment
+1 Ха-ха, помислих си същото, след като прочетох въпроса (обаче разгледах кода, за да потвърдя хипотезата си). ;-) - person Frerich Raabe; 13.04.2012
comment
това е кодът за тестване, опитвам се да използвам strlen(fileBuff), но той връща 1. Както sizeof(), така и strlen са за проверка дали файловият буфер е неправилно разпределен. - person panda; 13.04.2012

Размерът на указател (char *) на вашата (32-битова) платформа винаги е 4.

Не можете да използвате sizeof, за да определите колко памет е разпределена за буфер.

За да проверите дали указателят е разпределен, проверете върнатата стойност на malloc():

fileBuff = malloc(size);

if (fileBuff == 0) {
   fprintf(stderr, "Error allocating %d bytes.\n", size);
   abort();
}
person Linus Kleen    schedule 13.04.2012

sizeof се оценява по време на компилиране, тъй като вие питате за sizeof от filebuf, което е char* компилаторът изчислява, че е 4 байта (тъй като размерът на указателя е 4 байта във вашата платформа) и го отпечатва. malloc, което направихте, няма нищо общо с sizeof.

person Asha    schedule 13.04.2012

Освен неправилното използване на sizeof() можете да вземете предвид още 2 мисли:

Ако е само за копиране на файл: Не се опитвайте да изобретявате колелото и просто използвайте функцията system() и извикайте OS програмата, предназначена за това (cp в unix , копиране на DOS/Windows).

Ако е с цел обучение и затова настоявате да го направите сами: Не се опитвайте да прочетете целия файл и след това да го напишете отново, а четете и пишете част по част. Използването на големи размери на буфера води само до обезценяване на кеша на процесора. Обикновено съвпадението на размера на буфера на файловата система или проста част от него е размер на goot chunk, така че псевдокодът трябва да изглежда така:

open input file for reading
open output file for writing
as long as read from input file BUFSIZE bytes and read bytes > 0
     do write read data to output file
close input file
close output file

(и не забравяйте да проверявате за I/O грешки след всяко извикване на I/O рутина!)

И последна забележка: Не използвайте fgets(), освен ако не сте сигурни, че винаги е обикновен текстов файл. Ако решите да използвате fread()/fwrite(), вие сте спасени, дори ако това е двоичен файл (а освен това е по-бърз).

person ktf    schedule 13.04.2012