Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 29.09.2015, 00:36   #1
TotEnot
Пользователь
 
Регистрация: 28.09.2015
Сообщений: 11
По умолчанию Си. Работа с текстом. Общие моменты.

Добрый вечер.

Хочу выяснить несколько вопросов.

Сначала опишу, что хочу сделать.

В командной строке ввожу через запятую имена текстовых файлов.
Создаю массив_1, в который записываю имена текстовых файлов (т.к. хочу их проанализировать) через запятую.
Далее создаю массив_2, куда хочу записать всю информацию из файлов.

В связи с чем несколько вопросов:

1. Заранее число файлов и количество слов в каждом из них мне не известно. Т.е. мне надо создать динамический массив. В найденных примерах динамический массив инициализируется так:

Код:
float *p,d;
int i,n;
printf("\n input n:");
scanf("%d",&n);
p=(float *)malloc(n*sizeof(float));
for (i=0;i<n;i++)
Т.е. несмотря на то, что здесь фигурирует тип float, а не нужный мне char, программа все таки запрашивает размер массива n, а мне он не известен. Разъясните, пожалуйста, как мне поступать, если n мне неизвестна.

2. Следующий вопрос: у меня есть массив_1 с именами файлов, которые перечислены через запятую. Допустим, я смогу читать этот массив до запятой, как мне это прочитанное передать в функцию открытия файла в качестве его имени?

3. Считывая текстовые файлы в массив поочередно, буду ли я иметь в массиве несколько знаков ‘\0’, которые будут как бы разделителями текстов из разных файлов?

Спасибо если прочитаете и поясните! : )
TotEnot вне форума Ответить с цитированием
Старый 29.09.2015, 08:54   #2
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Цитата:
Разъясните, пожалуйста, как мне поступать, если n мне неизвестна
Код:
//-----------------------------------------------------------------------
//----------------------read_string_and_allocate-------------------------
//-----------------------------------------------------------------------
//Чтение строки произвольной длины из потока ввода
char * read_string_and_allocate ()
{
    int buffer_size = 64 ;//Размер буфера для чтения
    int buffer_size_divizer = 1 ; //Делитель для размера буфера. Изначально равен 1, далее станет понятно почему
    int offset_in_buffer = 0 ; //Смещение в буфере изначально равно нулю
    int length ;
    char * buffer = (char*)malloc ( buffer_size ) ; //Выделяем память под буфер
 
    if ( buffer == NULL ) //Если не удалось выделить, то
    {
        return NULL ; //Возвращаем ноль
    }
    buffer[0] = '\0' ;
    //Цикл до тех пор, пока не считаем всю строку целиком в буфер
    while ( 1 )
    {
        //Считываем строку из потока ввода
        //Причем считываем в буфер, со смещением равным offset_in_buffer
        //В качестве размера буфера передаем отношение размера буфера к делителю(buffer_size_divizer)
        if ( fgets( buffer + offset_in_buffer , buffer_size/buffer_size_divizer , stdin ) == NULL )
        {
            //Если нарвались на ошибку чтения, то выводим сообщение об ошибке
            printf ("\nRead error. Please, try again\n") ;
            fflush(stdout) ;//сбрасываем поток вывода
            fscanf ( stdin , "%*[^\n]" ) ; //Считываем символы, оставшиеся в потоке ввода
            free (buffer) ;//Освобождаем память, занятую буфером
            return NULL ; //Возвращаем ноль
        }
        else //Если прочитали успешно, то
        {
            //Вычисляем размер считанной строки (не считая '\0') и не считая ранее считанных символов (это контролируется смещением)
            length = strlen (buffer+offset_in_buffer) ;
            if ( buffer[length-1+offset_in_buffer] != '\n' )
                            //Если последний символ в строке (опять же, смещение контролирует начало отсчета, 
                                                 чтобы не считать уже считанные ранее символы) не равен '\n' ,
            //значит считали еще не все символы из потока
            {
                //Увеличиваем размер буфера равным в два раза больше текущего
                buffer_size *= 2 ;
                char * buffer_temp = buffer ;//Сохраняем указатель на буфер, чтобы в случае ошибки освободить память
                //Перевыделяем память нового размера
                //realloc сам скопирует старые даные в новую память
                buffer = (char*)realloc ( buffer , buffer_size ) ;
                if ( buffer == NULL ) //Если память выделить не удалось, то
                {
                    free ( buffer_temp ) ; //Освобождаем память
                    return NULL ; //вернем 0
                }
                //Теперь у нас доступна только половина буфера
                //ведь в первой половине буфера у нас находятся символы
                //уже считанные ранее, поэтому
 
                //К текущему смещению прибавляем длину строки, это
                //позволит потом считывать строку дальше в буфер со смещением, не задевая уже считанные символы
                offset_in_buffer += length ;
                //Устанавливаем делитель для размера буфера
                //это укажет, что теперь нам доступен не весь размер буфера, а лишь половина
                buffer_size_divizer = 2 ;
                //в результате это приведет к чтению только во вторую половину буфера без переполнения
            }
            else //Если же последний считанный символ равен '\n', то
            {
 
                buffer[length-1+offset_in_buffer] = '\0' ; //Заменяем символ конца строки на символ '\0'
                break ;//и выходим из цикла
            }
        }
    }
    return buffer ; //Возвращаем указатель на буфер со строкой
}
Пользуйтесь, возможно, придется немного переделать, если используется старый добрый Си (например, перенести объявление всех переменных в начало функции, изначально писалоси для Си, затем правилось уже без учета старенькой Сишки). Ошибки в поток ошибок выводить бы не мешало, ну и другие легко поправимые вещи.

Цитата:
Допустим, я смогу читать этот массив до запятой, как мне это прочитанное передать в функцию открытия файла в качестве его имени?
Можете, например, использовать strtok или что-то подобное для разбиение строки по запятым.
Цитата:
Считывая текстовые файлы в массив поочередно, буду ли я иметь в массиве несколько знаков ‘\0’, которые будут как бы разделителями текстов из разных файлов?
Как напишите, так и будет. Корректный ответ при такой постановке вопроса Вам врядли кто-то даст.

Последний раз редактировалось Stilet; 29.09.2015 в 09:03.
Croessmah вне форума Ответить с цитированием
Старый 29.09.2015, 20:59   #3
TotEnot
Пользователь
 
Регистрация: 28.09.2015
Сообщений: 11
По умолчанию

Большое спасибо за код.
Скажите, пожалуйста, приведенное решение - самое простое для подобной задачи? Отсутствие опыта и глубокого понимания Си мне пока не позволяют осознать приведенное Вами решение настолько, чтобы самостоятельно его применять
TotEnot вне форума Ответить с цитированием
Старый 29.09.2015, 22:53   #4
anticlown111
Пользователь
 
Регистрация: 16.09.2015
Сообщений: 10
По умолчанию

Цитата:
Сообщение от TotEnot Посмотреть сообщение
Добрый вечер.

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


2. Следующий вопрос: у меня есть массив_1 с именами файлов, которые перечислены через запятую. Допустим, я смогу читать этот массив до запятой, как мне это прочитанное передать в функцию открытия файла в качестве его имени?

3. Считывая текстовые файлы в массив поочередно, буду ли я иметь в массиве несколько знаков ‘\0’, которые будут как бы разделителями текстов из разных файлов?

Спасибо если прочитаете и поясните! : )
Если вы запускаете программу через командную строку то вы можете задать аргументы для функции main:

Код:
int main(int argc,char  **argv)
При запуске программы напишите нужные вам имена файлов. Например вы запускаете программу так: ./a.out in.txt out.txt . Тогда количество аргументов argc=3, а argv[1] и argv[2] будут строками содержащие имена нужных вам файлов (в argv[0] будет содержаться строка "./a.out"). По-моему в конце каждой этой строки дописывается нулевой символ '\0', проверьте. (Вообще говоря в Си этот символ нужен как раз для того чтобы определить конец строки)

Чтобы открыть эти файлы вам нужна функция fopen (почитайте про нее). Например чтобы работать с файлом in.txt в эту функцую вам надо просто передать argv[1].

Цитата:
Сообщение от TotEnot Посмотреть сообщение
Заранее число файлов и количество слов в каждом из них мне не известно. Т.е. мне надо создать динамический массив. В найденных примерах динамический массив инициализируется так:
Это смотря какую информацию вы хотите из этих файлов извлекать, часто можно обойтись и без массивов. Но уж если вам так хочется создать массив ровно под количество символов в файле, то можно пройтись по всем файлу, посчитать кол-во элементов, а потом переместить указатель обратно на начало файла.(для этого можно просто закрыть и снова открыть файл, хотя так делать не очень хорошо).
anticlown111 вне форума Ответить с цитированием
Старый 29.09.2015, 23:49   #5
TotEnot
Пользователь
 
Регистрация: 28.09.2015
Сообщений: 11
По умолчанию

Цитата:
Сообщение от anticlown111 Посмотреть сообщение

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

Последний раз редактировалось TotEnot; 29.09.2015 в 23:51.
TotEnot вне форума Ответить с цитированием
Старый 30.09.2015, 00:38   #6
anticlown111
Пользователь
 
Регистрация: 16.09.2015
Сообщений: 10
По умолчанию

Например так:
Код:
int c;
int kolvo=0;
while( (c=getc(in)) != EOF) 
kolvo++;
anticlown111 вне форума Ответить с цитированием
Старый 30.09.2015, 05:44   #7
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,709
По умолчанию

Или просто сделать fseek + ftell
p51x вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Работа с текстом Yrec Паскаль, Turbo Pascal, PascalABC.NET 5 01.02.2012 11:30
Работа с текстом nikolj HTML и CSS 16 10.06.2011 14:33
[Проблемка] Не могу понять некоторые моменты в borland c++ alex4718 Общие вопросы C/C++ 2 20.03.2010 10:56
Работа с текстом Sanek_ntsk Общие вопросы C/C++ 10 12.01.2008 19:42
Администрирование\управление компьютером\Общие папки\Общие ресурсы\прекратить общий доступ lm_strj Безопасность, Шифрование 2 13.10.2007 21:28