Помогите с fopen(), FileOpen()

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Владмир
Сообщения: 16
Зарегистрирован: 17 авг 2007, 16:42
Откуда: Samara

20 авг 2007, 10:39

Привет народ!

Помогите кто-нибудь, не могу разобраться с записью и чтением файлов, с помощью WinApi :(
функций (FileOpen(<2 параметра>) , FileRead(<3 параметра>) и FileWrite(<3 параметра>)). Открываю файл, считываю оттуда символ , дальше хочу изменить его на какой-либо другой при помощи switch() :
---------------------//<Отрывок проги>
void __fastcall TMainForm::GetChar()
{
char buf[1]; // можно заменить на char *buf; - без разницы
int fo,fw;
fo=FileOpen(OpenDialog1->FileName ,OF_READ); // можно во время работы проги выбрать файл
fw=FileOpen(Edit1->Text ,OF_WRITE); // можно во время работы проги выбрать файл
while(true)
{
FileRead(fo, buf ,1);
switch(buf) // тут постоянно ошибка
{
case 'q':buf='й'; break; // тут постоянно ошибка
case 'w':buf='q';break; // тут постоянно ошибка
case 'e':buf='p';break; // тут постоянно ошибка
}
if(feof) break;
FileWrite(fw, buf , 1); // тут постоянно ошибка
}
Close(fo); Close(fw);
}
но т.к. тип второго параметра у FileRead(<3 параметра>) и FileWrite(<3 параметра>) есть <void *Buffer> и < const void *Buffer>, что не является значением <LValue>, поэтому компилятор пишет ошибку : "Switch parameters must be LValue."
Если эти API ф-ии заменить поточными fopen(fo,"r"); fgetc(fo); fwrite(fr); то файлы при этом должны быть строго определены и во время работы проги нельзя самому их выбрать (FILE *fo, *fw - тип <const char>), а от этого она только проигрывает (хотя ошибка с switch() - ами пропадает).
Работаю в C++Builder 6.0.
Операционка MS WinXP.
Подскажите кто-нибудь можно ли как-то разрешить эту проблему, пожалуйста!!!
------------------------
Заранее признателен Владмир.
BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

20 авг 2007, 13:11

У тебя buf описан как массив. Массив в операторе switch, разумеется, использовать нельзя.

Код: Выделить всё

switch(buf[0])
{
case 'q':buf[0] ='й'; break;
case 'w':buf[0] ='q';break;
case 'e':buf[0] ='p';break;
}
char buf[1]; // можно заменить на char *buf; - без разницы
Разница есть и большая. *buf - лишь указатель. Который без инициализации указывает на совершенно произвольную область памяти. Если попробовать туда что-то записать, память будет разрушена.
Владмир
Сообщения: 16
Зарегистрирован: 17 авг 2007, 16:42
Откуда: Samara

21 авг 2007, 16:39

2 BBB:

Не очень помогло, но всё равно спасибо.
BBB писал(а): Разница есть и большая. *buf - лишь указатель.

Пардон, конечно же разница есть, я имел ввиду что компилятор это проглатывает и не пишет ошибки. :D
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

22 авг 2007, 09:41

Владмир писал(а):2 BBB:
Не очень помогло, но всё равно спасибо.
Так ты сделал switch(buf[0]) ?
Владмир писал(а): Пардон, конечно же разница есть, я имел ввиду что компилятор это проглатывает и не пишет ошибки. :D
Конечно не пишет, он конвертирует массив в указатель на первый элемент при вызовах функций. Если передаешь уже указатель, то нужды конвертировать нет. Только проблема в том, что этот указатель не инициализирован.
2B OR NOT(2B) = FF
Владмир
Сообщения: 16
Зарегистрирован: 17 авг 2007, 16:42
Откуда: Samara

22 авг 2007, 17:46

Absurd писал(а):Так ты сделал switch(buf[0]) ?

Нет, ведь массив должен содержать минимум 1 элемент, но это всё равно массив и в switch()'е та же ошибка.
Absurd писал(а): Конечно не пишет, он конвертирует массив в указатель на первый элемент при вызовах функций. Если передаешь уже указатель, то нужды конвертировать нет. Только проблема в том, что этот указатель не инициализирован.

А как его инициализировать? С помощью "this" ? (я немного путаюсь в массивах и указателях...)
BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

22 авг 2007, 18:26

Владмир писал(а):я немного путаюсь в массивах и указателях...)
Массив "чего-то" (например, char-ов) - это набор из нескольких этих "чего-то". Т.е.
char ac [10] - набор 10-ти перемеррых типа char.
Указатель на "что-то" - это адрес памяти (число), по которой находится переменная типа "что-то".

Пример из жизни. Улица - это массив домов. Указатель на некий дом - это бумажка, на которой написан адрес этого дома.

Вообще говоря, меня тоже несколько смущает эта СИ-шная "вольность" - смещивать (на уровне языка) понятия "массив" и "указатель". Сам начинал с Паскаля, там такого "бардака" нет. В результате этого в Cи возможны ошибки из-за невнимательности или недопонимания. Например, в пр-ру, куда по смыслу тербуется передать буфер (массив) можно передать указатель, и все накроется медным тазом.
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

22 авг 2007, 18:41

Владмир писал(а):Нет, ведь массив должен содержать минимум 1 элемент, но это всё равно массив и в switch()'е та же ошибка.
В С/C++ и во всех современных языках (Java, C#, Perl, etc) индексация массивов всегда идет с нуля (0). Массив типа char buff[1] имеет всего один элемент с индексом 0. Массив типа char buff[2] имеет два элемента с индексами 0 и 1. Итд по индукции.
Выражение "buff[0]" в обоих случаях означает элемент массива (то есть просто char), а не сам массив.

Код: Выделить всё

#include <iostream>

int main(int argc, char** argv) {
	char buff[1] = {'a'};
	switch (buff[0]) {
		case 'a':
			std::cout<<"Success!!!\n";
			break;
		default:
			std::cout<<"Fail =(((((((\n";
	}
	return 0;
}
Замечательно компилируется и выдает "Success!!!". Не знаю как ты там изнасиловал CBuilder что он у тебя не работает.
Владмир писал(а): А как его инициализировать? С помощью "this" ? (я немного путаюсь в массивах и указателях...)
С помощью операции "Взять адрес '&'" но это изврат в нашем случае - даю только как пример.

Код: Выделить всё

char c;
char *buff = &c;
2B OR NOT(2B) = FF
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

22 авг 2007, 18:45

BBB писал(а):Сам начинал с Паскаля, там такого "бардака" нет.
Offtopic: зато в Паскале нельзя написать обобщенную функцию, которая к примеру сортирует массив любой длины состоящей из любых структур, что бесит.
2B OR NOT(2B) = FF
Владмир
Сообщения: 16
Зарегистрирован: 17 авг 2007, 16:42
Откуда: Samara

23 авг 2007, 16:21

Absurd писал(а): ... Выражение "buff[0]" в обоих случаях означает элемент массива (то есть просто char), а не сам массив.

Код: Выделить всё

    switch (buff[0]) {
        case 'a':
            std::cout<<"Success!!!\n";
            break;
        default:
            std::cout<<"Fail =(((((((\n";
    }
 
Замечательно компилируется и выдает "Success!!!". Не знаю как ты там изнасиловал CBuilder что он у тебя не работает.

Ну конечно же это я виноват, проглядел, что у меня: "switch(&buf[0])" , Спасибо! :)

-------------------------------------------
А вообще у меня получилось почти всё со switch().
Прорамма читает символ, меняет его, записывает изменённый в другой файл,
НО записывает только 1 символ, не зависимо сколько их в читаемом файле!

---------не много подкоректировал:
char buf[1];
int all=0; // счетчик цикла-для проверки
char *buf1;
while(!eof(fr))
{
FileRead(fr,&buf[0],1);
switch(buf[0])
{
case 'q':buf1="й" ; break;
case 'w':buf1="q" ;break;
case 'e':buf1="p" ;break;
}
FileWrite(fw, buf1 , 1);
all++;
}
FileClose(fr);
FileClose(fw);
Label1->Caption=IntToStr(all);
}
--------------------------------
"all" - у меня всегда 0, т.е. цикл не проходит ни разу, значит он сразу находит в читаемом файле
"eof()" ! Хотя этот файл не пуст. Или "fr" это не идентификатор файла?

Подскажите, как правильно определять конец файла?
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

24 авг 2007, 14:36

Что за "FileRead"? Почему не fread() / fwrite() / feof() ?
Знаю про операции безбуфферного чтения файлов _read() из <io.h> и ReadFile() из <windows.h>, FileRead() не знаю.
2B OR NOT(2B) = FF
Ответить