2017-02-21 8 views
2

Насколько я понимаю, передача указателя на функцию по существу передает копию указателя на функцию в C. У меня есть указатель FILE, который я передаю функции func(), func() читает строку из файла, а затем, когда мы вернуться к main(). Я прочитал еще одну строку из файла, используя тот же указатель FILE.Почему указатель FILE после передачи функции изменяется, когда возвращается в main на C?

Однако, хотя я бы предположил, что я прочитал строку ровно с того момента, как был вызван func(), я действительно прочитал следующую строку после того, что прочитало func(). Не могли бы вы объяснить, почему так выглядит FILE?

Это мой код:

#include <stdio.h> 

#define STR_LEN 22 

void func(FILE *fd); 

int main() { 
    FILE *fd; 
    char mainString[STR_LEN]; 
    if (!(fd = fopen("inpuFile", "r"))) { 
     printf("Couldn't open file\n"); 
     fprintf(stderr, "Couldn't open file\n"); 
    } 

    func(fd); 
    fgets(mainString, STR_LEN, fd); 
    printf("mainString = %s\n", mainString); 

    fclose(fd); 

    return 0; 
} 

void func(FILE *fd) { 
    char funcString[STR_LEN]; 
    fgets(funcString,STR_LEN, fd); 
    printf("funcString = %s\n", funcString); 
} 
+1

Могу ли я просто сказать, что 'fd' (который многие будут считать« файловым дескриптором », т. Е.' Int' из 'open()') является довольно плохим именем для переменной типа 'FILE *'? Очень смущает. – unwind

ответ

1

Потому что FILE указатель указывает на некоторые данные, которые получает измененные, когда файл чтения/записи.

Таким образом, указатель не изменяется (по-прежнему указывает на структуру обработчика файла), но данные, указанные структурой, выполняются.

Попробуйте пропустить указатель как const FILE *, вы увидите, что не можете, потому что операция fread (и другие) изменяет указанные данные.

Один из способов - дублировать файловый дескриптор, который dup делает, но не работает на буферизованный объект FILE, только с файловыми дескрипторами.

3

Однако, в то время как я предположил бы, что я прочитал линию точно от до того, как называется функ ...

Я не могу себе представить, почему бы вы представить себе, что. Что делать, если FILE* ссылается на сетевое соединение, которое вообще не имеет возможности воспроизведения, где чтение является потреблением. Где будет храниться строка, чтобы вы могли ее прочитать? Этого было бы совершенно невозможно.

Я бы не только не представьте, что это своего рода сумасшедший.

Насколько я понимаю, передавая указатель на функцию, по существу, передает копию указателя на функцию в С.

Correct. Но копия указателя указывает на тот же объект. Если я укажу на машину, и вы меня скопируете, вы укажете на тот самый автомобиль, на который я указываю.

1

Проблема в вашем первоначальном заявлении: As far as I understand passing a pointer to a function essentially passes the copy of the pointer to the function in C.

Это не сильно изменится, так как все, что вы просматриваете как указатель, по-прежнему содержит местоположение FILE, к которому вы обращаетесь, вся суть использования указателей в качестве аргументов для функции на C, заключается в том, что вы можете изменить определенное значение выходит за рамки функции.

Например, общее использование целочисленного указателя в качестве аргумента функции:

void DoSomethingCool(int *error); 

Теперь, используя этот код, чтобы поймать ошибку будет выглядеть так:

int error = 0; 
DoSomethingCool(&error); 

if(error != 0) 
    printf("Something really bad happened!"); 

Другими словами, указатель будет фактически изменить целочисленную ошибку, обратившись к ее местоположению и записывая на нее.

Важно помнить, что во избежание подобных недоразумений следует признать, что все указатели есть, по существу, это адрес чего-то.

Таким образом, можно (теоретически, упрощая все много) думать о int *, как просто int, значение которого случается адрес некоторой переменной, для FILE *, вы можете думать об этом как int, где значение int является адресом переменной FILE.

+0

Вы правы, удалите его. –

1

FILE *fd является указателем только в том смысле, что его реализация использует конструкцию C, называемую «указателем». Это не указатель в смысле представления позиции файла.

FILE *fd представляет ручку для файлового объекта внутри библиотеки ввода/вывода, struct, который включает фактическое положение файла. В очень упрощенном виде вы можете думать о fd как о указателе на указатель файла.

Когда вы проходите fd вокруг своей программы, процедуры ввода-вывода вносят изменения в положение файла. Эта позиция является общей для всех пользователей fd. Если func() вносит изменения в эту позицию, прочитав некоторые данные или вызвав fseek, все пользователи того же fd увидят обновленную позицию.