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

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

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 14.12.2011, 10:36   #1
dr.Chas
***
Участник клуба
 
Аватар для dr.Chas
 
Регистрация: 30.07.2007
Сообщений: 1,162
По умолчанию Способы считывания строки не известной длины (си)

Что то не могу понять логику работы. Допустим есть файл, из него нужно считать строки и сохранить их для дальнейшей работы. Размер файла и строк не известен. Читаю пару книг, смотрю в интернете, но везде приводят примеры с заранее фиксированном кол-вом символов. Можно но словах, но если не трудно можно не большим примером. Как такое вообще делается.
dr.Chas вне форума Ответить с цитированием
Старый 14.12.2011, 11:15   #2
dr.Chas
***
Участник клуба
 
Аватар для dr.Chas
 
Регистрация: 30.07.2007
Сообщений: 1,162
По умолчанию

Написал и вроде сам разобрался. Не знаю, может я не правильно что делаю?

Код:
char *word=NULL;
int i, c;

while ((c=getc(f))!=EOF) {
			word=realloc(word,i+1);
			i++;
			
			if (c=='\n') { 			
				puts(word);
				i=0; 
			} else word[i-1] = c;
}

free(word);
dr.Chas вне форума Ответить с цитированием
Старый 14.12.2011, 11:23   #3
Felian
Пользователь
 
Регистрация: 13.11.2011
Сообщений: 24
По умолчанию

Можно начать считывать файл в первом проходе, подсчитывая количество переносов строк (символы с кодами 10 и/или 13) и количество символов (расстояние) между началом файла / предыдущим переносом строки и очередным переносом строки. Это расстояние будет размером строки. Затем динамически malloc или new выделять память под эти строки для чтения их во втором проходе.

Ну или может как-то ещё средствами C++.

realloc - это некрасивое решение. Проще прочитать два раза, я думаю.

Последний раз редактировалось Felian; 14.12.2011 в 11:26.
Felian вне форума Ответить с цитированием
Старый 14.12.2011, 11:29   #4
dr.Chas
***
Участник клуба
 
Аватар для dr.Chas
 
Регистрация: 30.07.2007
Сообщений: 1,162
По умолчанию

Цитата:
Сообщение от Felian Посмотреть сообщение
Можно начать считывать файл в первом проходе, подсчитывая количество переносов строк (символы с кодами 10 и/или 13) и количество символов (расстояние) между началом файла / предыдущим переносом строки и очередным переносом строки. Это расстояние будет размером строки. Затем динамически malloc или new выделять память под эти строки для чтения их во втором проходе.

Ну или может как-то ещё средствами C++.

realloc - это некрасивое решение. Проще прочитать два раза, я думаю.
Да о прочтении два раза уже думал, но думал есть решение проще. Если и правда первый вариант предпочтительней то выберу его.
dr.Chas вне форума Ответить с цитированием
Старый 14.12.2011, 17:54   #5
Blade
Software Engineer
Участник клуба
 
Аватар для Blade
 
Регистрация: 07.04.2007
Сообщений: 1,618
По умолчанию

Подход правильный - читать посимвольныо, пока не встретится конец строки. Только реализация немножко не правильная.
Вместо того, чтобы все время дописывать один символ в вашу строку - создайте большой буфер, и читайте в него, когда нашли символ конца строки, создаете новую строку, размером равную количеству символов в буфере, и переписываете содержимое буфера в нее. Только не забывайте следить, чтобы буфер не переполнился. Если к моменту, когда буфер закончился, символ конца строки еще не прочитан, можно либо с помощью realloc() увеличить буфер, либо переписать содержимое в новую строку, и начать читать в буфер с начала, а потом дописать прочитанное в первую строку, опять же увеличив ее с помощью realloc() (я бы выбрал второй вариант).
Читать файл два раза - самое плохое решение, из всех тут рассмотренных
Мужество есть лишь у тех, кто ощутил сердцем страх, кто смотрит в пропасть, но смотрит с гордостью в глазах. (с) Ария
Blade вне форума Ответить с цитированием
Старый 15.12.2011, 08:22   #6
dr.Chas
***
Участник клуба
 
Аватар для dr.Chas
 
Регистрация: 30.07.2007
Сообщений: 1,162
По умолчанию

Код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int openFile(char **name, FILE **f) {
	if ((*f=fopen(*name, "r"))==NULL) return 0;
	else return 1;
}

void bufferSize(char **str, int size, int cons) {
	*str=realloc(*str, (size+cons)*sizeof(char));
}

void newBufferSize(char **str, int cons) {
	*str=(char*) malloc(cons*sizeof(char));
}

void main() {
	FILE *f;
	char *name="test.dat", *str=NULL, **arrstr=NULL;
	int i, c, j, pam=0, cns=255;

	newBufferSize(&str, cns);
	if (openFile(&name, &f)==1) {
		i=0;   j=0;
		while ((c=getc(f))!=EOF) {						
			if (c=='\n') { 
				//str=realloc(str,j+1);	
				i++;
						
				pam=pam+i;			
				arrstr=realloc(arrstr, pam);
				j++;
				arrstr[j-1]=str;					
							
				str=NULL;
				newBufferSize(&str, cns);
				i=0; 
				
			} else {
				i++;
				if ((i % cns)==0) {					
					bufferSize(&str, i, cns);
					printf("new_size=%d ", sizeof(&str));
				}			
				str[i-1] = c;					
				
			}
		}

		printf("строки файла из памяти: \n");
		for (i=0; i<j; i++) {
			puts(arrstr[i]);
			
		}		
		
		free(arrstr);
		free(str);
	} else puts("не удалось открыть файл\n");
	
}
Посмотрите кто нибудь, велосипедов не нагородил?
dr.Chas вне форума Ответить с цитированием
Старый 15.12.2011, 09:18   #7
mrChester
Я
Форумчанин
 
Аватар для mrChester
 
Регистрация: 24.04.2010
Сообщений: 693
По умолчанию

Код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int openFile(char **name, FILE **f) {
	if ((*f=fopen(*name, "r"))==NULL) return 0;
	else return 1;
}

void bufferSize(char **str, int size, int cons) {
	*str=(char*)realloc(*str, (size+cons)*sizeof(char));
}

void newBufferSize(char **str, int cons) {
	*str=(char*) malloc(cons*sizeof(char));
}

void main() {
	FILE *f;
	char *name="test.dat", *str=NULL, **arrstr=NULL;
	int i, c, j, pam=0, cns=255;

	newBufferSize(&str, cns);
	if (openFile(&name, &f)==1) {
		i=0;   j=0;
		while ((c=getc(f))!=EOF) {						
			if (c=='\n') { 
				//str=realloc(str,j+1);	
				i++;
				str[i-1] = '\0';
				pam=pam+i;			
				arrstr = (char**)realloc(arrstr, pam);
				j++;
				arrstr[j-1]=str;					

				str=NULL;
				newBufferSize(&str, cns);
				i=0; 

			} else {
				i++;
				if ((i % cns)==0) {					
					bufferSize(&str, i, cns);
					printf("new_size=%d ", sizeof(&str));
				}			
				str[i-1] = c;					

			}
		}
		str[i] = '\0';
		pam=pam+i-1;			
		arrstr = (char**)realloc(arrstr, pam);
		arrstr[j]=str;

		printf("строки файла из памяти: \n");
		for (i=0; i<=j; i++) {
			puts(arrstr[i]);

		}		

		free(arrstr);
		free(str);
	} else puts("не удалось открыть файл\n");
}
Имеются мелкие замечания по поводу написания кода, оптимизации. В целом этот вариант работает
Все персонажи вымышлены, все совпадения случайны.
Если жизнь игра, тогда я её разработчик ©.
mrChester вне форума Ответить с цитированием
Старый 15.12.2011, 09:25   #8
dr.Chas
***
Участник клуба
 
Аватар для dr.Chas
 
Регистрация: 30.07.2007
Сообщений: 1,162
По умолчанию

Код:
str[i-1] = '\0';
Сначала тоже его добавлял, но потом убрал. Т.к. вычитал, что компилятор его подставляет автоматически.
dr.Chas вне форума Ответить с цитированием
Старый 15.12.2011, 10:07   #9
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию

> dr.Chas
Насчёт количества строк понятно (malloc, realloc), но как быть если длина строки слишком большая. Пока не могу придумать. Наверное зависим от задачи. Например, можно переносить символы строки (которые не уместились в текущую), в следующую. Вариант с переносом возможен?

// readlines: считывает строки из файла в массив указателей на строки, возвращает количество считанных строк
// getline: считывает строку в s из файла, используется в readlines(), возвращает длину строки

Я немного переработал пример из K&R:
1. функция getline теперь считывает строку из файла (ранее из терминала).
2. в readline считывает все строки в массив указателей на char, используя malloc() для выделения памяти (ранее alloc)
3. указатель на файл передаю readlines, а потом в getline. По другому не смог придумать, как не передавать. Сделать глобальной pfile не получается.
4. В случае если длина строки слишком большая или количество строк слишком много, то выводится сообщение: "error: input file is too big"

Код:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXLINES 5000

int main () {
    int nlines;
    char* lineptr[MAXLINES];
    int readlines (char* lineptr[], int maxlines, FILE* pfile);

    char filename[] = "inputfile.txt";
    FILE* pfile = fopen(filename, "r");

    if (pfile == NULL) {
        printf("error in getline: can't open file \"%s\"\n", filename);
        return 1;
    }

    if ((nlines = readlines(lineptr, MAXLINES, pfile)) >= 0) {

        // actions
        printf("input file had been read\n");
    }
    else {
        printf("error: input file is too big\n");
    }

    fclose(pfile);
    return 0;
}

#define MAXLEN 1000

// readlines: считывает строки из файла
int readlines (char* lineptr[], int maxlines, FILE* pfile) {
    int nlines;
    int len;
    char line[MAXLEN];
    int getline(char line[], int max, FILE* pfile); 
    char* p;

    nlines = 0;
    while ((len = getline(line, MAXLEN, pfile)) > 0) {
        if (nlines < maxlines && (p = (char*) malloc(len)) != NULL) {
            line[len-1] = '\0';
            strcpy(p, line);
            lineptr[nlines++] = p;
        }
        else {
            return -1;
        }
    }
    return nlines;
}

// getline: считывает строку в s
int getline(char s[], int lim, FILE* pfile) {
    int c, i;

    for (i = 0; i<lim-1 && (c = fgetc(pfile)) != EOF && c != '\n'; i++) {
        s[i] = c;
    }

    if (c == '\n') {
        s[i++] = '\n';
    }

    s[i] = '\0';

    return i;
}
8Observer8 вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
вычисление длины строки fokinamasha Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 3 01.04.2011 22:06
Вычисление длины строки Agafon Microsoft Office Word 12 17.11.2010 15:43
измерение длины строки Agafon Общие вопросы Delphi 6 11.11.2010 15:13
Способы получения ссылки на ячейку при известном номере строки. Tidus Microsoft Office Excel 5 08.06.2010 09:33
Строки неизвестной длины в си abr_question Общие вопросы C/C++ 18 22.01.2010 00:26