Wczytywanie tekstu o dowolnej długości

0

Próbuje przestawić się z Delphi na C i brakuje mi dość mocno takiej "bezstresowej" obsługi stringów jaką ma Object Pascal :) . Czy jest w C jakaś funkcja która potrafi wczytać z wejścia dowolną ilość znaków alokując przy okazji dla nich pamięć ? W BCB wykombinowałem takiego dziwoląga:

char* str_scanf(){
  int n = 0;
  char c = 0;
  char *str = (char *) malloc(sizeof(char));

  while (c != 13){
    str = (char *) realloc(str, n + 1);
    c = getch();
    printf("%c", c);
    str[n++] = c;
  }
  str[n] = 0;
  printf("\n");
  return str;
}

Problem polega na tym, że musze działać na gcc w linuxie gdzie getch() nie ma. Może da się to zrobić inaczej ?

0

Jeśli użyjesz C++ to masz do dyspozycji funkcje getline(istream, string)

0

no to pod *niksami masz juz gotowa funkcje : man 3 getline :)

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int readline(char** ret){ // funkcja zwraca dlugosc ciagu bez znaku 0 - to samo co zwroci strlen lub -1 gdy zawiedzie getline
  ssize_t read;
  char* line=0; // NULL
  size_t len=0;
  if((read=getline(&line,&len,stdin))!=-1){
    // printf("%d %d %d %s",read,len,strlen(line),line); // debug code, odkomentuj i popatrz
    if(line[read-1]=='\n')line[--read]=0;   // zmieniamy znak konca linii na 0, skracamy ciag
    *ret=strdup(line);  // w ten sposob na wyjsciu masz ciag ktory zajmuje dokladnie tyle ile potrzebuje a nie tyle ile zostalo mu przydzielone
    if(!*ret){
      *ret=line; // a to na wszelki wypadek, gdyby strdup nie moglo przydzielic pamieci, wtedy masz tyle pamieci ile getline uwazalo za stosowne pobrac (zmienna len)
      return read; // i omijamy wtedy zwalnianie
    }
  }
  free(line);
  return read;
}

main(){
  char* s;
  int i;
  while((i=readline(&s))>0){
    printf("%d %s\n",i,s);
    free(s);
  }
  return 0;
}
0

Z waszym wypowiedzi wynika że getline mozna uzywać prz c++ - niestety ja jestem ograniczony do GCC więc getline odpada :/ .

0

[glowa] a niby jak to kompilowalem ?

http://flabra.carramba.homelinux.org/temp/readline.png

0
flabra napisał(a)

[glowa] a niby jak to kompilowalem ?

http://flabra.carramba.homelinux.org/temp/readline.png

Ja niestety znam się na linuxie równie słabo jak na c, więc czy móglbyś mi wyjaśnić czemu mnie ta kompilacja wygląda tak http://www.delphi.is.net.pl/readline.png ?

0

odpal ldconfig. poza tym : 'Both getline() and getdelim() are GNU extensions. They are available since libc 4.6.27.' - masz ?. to nie jest wina kompilatora, ani braku nagłówków, tylko konfiguracji systemu, bibliotek i ld.

0

Zapewne nie mam skoro nie działa... używam linuksowego konta na agh i żadnych szczegółów konfiguracji nie znam :/.

0

Pewnie piszesz gcc zamiast g++ :)
Jak chcesz skompilować c++ to używaj kompilatora c++, a nie c :)

0
Dungeon_Master napisał(a)

Pewnie piszesz gcc zamiast g++ :)

Tak, Sherlocku !! :d A teraz przeczytaj dokładnie co napisałem na końcu swojego pierwszego posta :) .

0

mozesz zawsze pomeczyc sie czyms takim (ja tak robilem jak pisalem ksiegie gosci w cgi) :

while (fgetc(wpisy)!='\n') i++;
fseek(wpisy,-i-2,1); 
string = (char*)malloc(sizeof(char)*(i+1));
fread(string,sizeof(char),i,wpisy);
*(string+i)='\0';

w kazdym razie.. jakos tak to wygladalo [;

pamietam tylko, ze wczytywany plik musial miec new line at the end of file [;

dawno pisalem, wiec sie nie smiac..

0

while (fgetc(wpisy)!='\n') i++;
fseek(wpisy,-i-2,1);
string = (char*)malloc(sizeof(char)*(i+1));
fread(string,sizeof(char),i,wpisy);

Troche nieelegancko, 2x czytać plik, i jeszcze fseek co linie. Dynamiczny bufor by sie zdał.

#include <stdio.h>

#define BUFF_SIZE      100  //dmyślny rozmiar bufora
#define BUFF_INCREMENT 50   //o ile zwiekszamy bufor w przypadku przepełnienia

//funkcja kopiuje "n" bajtów w nowozaalokowany blok pamięci
void *memdup(const void *src, size_t n)
{
   return memmove(malloc(n), src, n);
}

//funkcja zwiękasza zaalokowany blok pamięci pomiędzy "begin" a "end" o "inc"
//bajtów i zwraca stary rozmiar
int incalloc(void **begin, void **end, size_t inc)
{
   size_t size = *end - *begin;
   *begin = realloc(*begin, size + inc);
   *end = *begin + size + inc;
   return size;
}

int main()
{
   FILE* wpisy = fopen("c:\\a.txt", "rt");

//bufor na jedną linie tekstu
   char* Buffer = malloc(BUFF_SIZE);

//wskaźnik końca buforu, wskazuje na pierwszy element ZA buforem
   char* BuffEnd = Buffer + BUFF_SIZE;

//wskaźniki do wczytywanych linii (też można dynamicznie zmieniać jej rozmiar)
   char* lines[255];

   int num = 0; //numer wczytywanej linii
   char* ch = Buffer; //wskaźmik do kolejnych bajtów bufora

   while((*ch = fgetc(wpisy)) != EOF) //znaki czytane prosto do bufora
   {
      if(*ch == '\n')
      {
         *ch = '\0'; //zamiń znak '\n' na '\0'
         lines[num++] = memdup(Buffer, ch - Buffer + 1); //skopiuj bufor
         ch = Buffer; //powrót wskaźnika na początek bufora
      }
      else if(++ch == BuffEnd) //przepełnienie bufora
      {
         //alokuje nową pamięć dla bufora i ustawia wskaźnik ch na
         //pierwszym dodatkowo zaalokowanym bajcie
         ch = incalloc(&Buffer, &BuffEnd, BUFF_INCREMENT) + Buffer;
      }
   }

   if(ch > Buffer) //gdy niepusta ostatnia linia
   {
      *ch = '\0'; //zamiń znak EOF na '\0'
      lines[num++] = memdup(Buffer, ch - Buffer + 1);
   }

   free(Buffer);

   int i;
   for(i=0; i<num; i++)
   {
      printf("%s\n", lines[i]);
   }
}
0

takie ot:
dryobates mi kiedys zwrocil uwage na jedna rzecz, jesli juz zmieniacie rozmiar przydzielonej pamieci, to nie o n bajtów, tylko 2x. w przykladzie wyzej jest skok o 50. co przy poczatkowym rozmiarze daje przyrost rzedu 50%, potem 33%, 25%, ... Skoro dane zajely juz bufor, to dodawanie coraz mniejszego procentu niewiele da, poniewaz prawdopodobienstwo ze dane znow przekrocza rozmiar bufora rosnie im wiekszy ten bufor jest. przy powiekszaniu 2x patrzac statystycznie nowe dane bedą zajmowały i tak więcej niż 50% wilekości bufora i jest spore prawdopodobienstwo, ze zajma wiecej. pozostała, niewykorzystana cześć zajmuje wtedy tylko ułamek całości bufora. do tego dochodzi dużo mniej operacji na pamieci i co za tym idzie dochodzi mniejsze prawdopodobienstwo ze wystapi blad jej przydziału, oraz bledow naruszenia ochrony pamieci w niezabezpieczonych kawalkach np.: 'memmove(malloc(n), src, n)'

// adf88 - komentarz do ogolnej tendencji, przyklady z twojego postu... bo twoj post jest pod reka akurat

0

adf88 czytanie znak po znaku to malo wydajne rozwiazanie normalnie odczytuje sie wartosci rzedu 128, 256, 1024, 2048 jednym wywolaniem funkcji np za pomoca fgets lub tez fscanf i dopiero pozniej w zaleznosci co zostalo odczytane inkrementuje sie bufor tak jak podal kolega wyzej powinien byc 2x wiekszy poza tym nie zapominaj ze przy alokacji pamieci czy tez realokacji nalezy sprawdzac czy nie wystapil blad u Ciebie tego nie widze.
//edit tak ja np kiedys rozwiazalem problem z getline w C pod winde

int fgetline(char **str, FILE *f)
{
	int ibo, offset, buflen;
	offset = 0;
	buflen = 1024;
	
	if (!(*str = (char*)malloc(sizeof(char)*buflen)))
	{
		printf("brak pamieci...");
		return -1;
	}
	
	while(fscanf(f, "%1023[^\n]%n", *str+offset, &ibo) > 0)
	{
		offset += ibo;

		if (offset >= buflen-1023) 
		{
			if (!(*str=(char*)realloc(*str, buflen<<=1)))
			{
				printf("blad podczas realokacji pamieci...");
				return -1;
			}
		} 
	}
	
	if (offset < buflen)
		if (!(*str=(char*)realloc(*str, offset)))
		{
				printf("blad podczas realokacji pamieci...");
				return -1;
		}
	
        fgetc(f);
	return offset;
}

mozna to zrobic jeszce bardziej optymalnie wykorzystujac fgets ale potrzebowalem zrobic aby przy powrocie dokladnie podawal mi dlugosc lini Od razu jaka odczytal wioec rozwiazanie z scanfem bylo idealne

1 użytkowników online, w tym zalogowanych: 0, gości: 1