2010-03-24 13 views
5

Jak odczytywać nieograniczoną liczbę znaków do zmiennej char* bez określania rozmiaru?Jak odczytać nieograniczoną liczbę znaków w C

Załóżmy na przykład, że chcę przeczytać adres pracownika, który może również przyjąć wiele wierszy.

+2

Poniższe odpowiedzi demonstrują mechanikę problemu i zachęcam do ich przestudiowania. Jedną z powszechnych implementacji jest 'getline'. – dmckee

+0

Musisz zacząć od upewnienia się, że twój sprzęt ma nieograniczoną pamięć! – theglauber

Odpowiedz

8

Musisz zacząć od "zgadywania" rozmiaru, jakiego się spodziewałeś, a następnie przydzielić bufor o dużej wartości, używając malloc. Jeśli okaże się to zbyt małe, użyjesz realloc, aby zmienić rozmiar bufora na nieco większy. Przykładowy kod:

char *buffer; 
size_t num_read; 
size_t buffer_size; 

buffer_size = 100; 
buffer = malloc(buffer_size); 
num_read = 0; 

while (!finished_reading()) { 
    char c = getchar(); 
    if (num_read >= buffer_size) { 
     char *new_buffer; 

     buffer_size *= 2; // try a buffer that's twice as big as before 
     new_buffer = realloc(buffer, buffer_size); 
     if (new_buffer == NULL) { 
      free(buffer); 
      /* Abort - out of memory */ 
     } 

     buffer = new_buffer; 
    } 
    buffer[num_read] = c; 
    num_read++; 
} 

Jest tuż przy mojej głowie, a może (czytaj: będzie prawdopodobnie) zawierają błędy, ale powinny dać dobry pomysł.

+1

@Codeka - powinieneś unikać 'x = realloc (x, newsize);' Jeśli realloc się nie powiedzie, stracisz oryginalny wskaźnik i stracisz pamięć. To powiedziawszy, jeden wyjątek od tej zasady jest w porządku, jeśli twoja polityka na niepowodzenie przydziału ma zakończyć proces. –

+0

Ale, uwaga ... jeśli realloc nie powiedzie się, wyciekłeś poprzedni wskaźnik bufora. Należy zrobić coś takiego, jak "void * sav = ptr; if ((ptr = realloc (ptr, newsiz)) == null) {free (sav); } ' –

+0

Dzięki chłopaki, to prawda. Zaktualizuję mój przykład ... minęło trochę czasu odkąd użyłem prostego C :) –

0

Co powiesz na umieszczenie bufora 1KB (lub 4KB) na stosie, czytanie do tego, aż znajdziesz koniec adresu, a następnie przydzielisz bufor o odpowiednim rozmiarze i skopiujesz do niego dane? Po powrocie z funkcji bufor stosu znika i masz tylko jedno połączenie z malloc.

+0

Co się dzieje, gdy adres jest większy niż bufor 1k lub 4k na stosie? – Gabe

+1

@gabe: Jak piszesz adres 4KB na kopercie? – tomlogic

+0

Brak znajomości rozmiaru ciągu wejściowego i próba odczytania go w buforze o stałym rozmiarze jest źródłem niezapowiedzianych problemów bezpieczeństwa w kodzie C. – Gabe

1

Wystarczyło odpowiedzieć Ex 7.1, str. 330 z C, autor: Ivor Horton, wydanie trzecie. Zajęło mu to kilka tygodni. Umożliwia wprowadzanie liczb zmiennoprzecinkowych bez wcześniejszego określenia liczby liczb wprowadzonych przez użytkownika. Przechowuje liczby w tablicy dynamicznej, a następnie wypisuje liczby i średnią wartość. Używanie Code :: Blocks z Ubuntu 11.04. Mam nadzieję, że to pomoże.

/*realloc_for_averaging_value_of_floats_fri14Sept2012_16:30 */ 

#include <stdio.h> 
#include <stdlib.h> 
#define TRUE 1 

int main(int argc, char ** argv[]) 
{ 
    float input = 0; 
    int count=0, n = 0; 
    float *numbers = NULL; 
    float *more_numbers; 
    float sum = 0.0; 

    while (TRUE) 
    { 
     do 
     { 
      printf("Enter an floating point value (0 to end): "); 
      scanf("%f", &input); 
      count++; 
      more_numbers = (float*) realloc(numbers, count * sizeof(float)); 
      if (more_numbers != NULL) 
      { 
       numbers = more_numbers; 
       numbers[count - 1] = input; 
      } 
      else 
      { 
       free(numbers); 
       puts("Error (re)allocating memory"); 
       exit(TRUE); 
      } 
     } while (input != 0); 

     printf("Numbers entered: "); 
     while(n < count) 
     { 
      printf("%f ", numbers[n]); /* n is always less than count.*/ 
      n++; 
     } 
     /*need n++ otherwise loops forever*/ 
     n = 0; 
     while(n < count) 
     { 
      sum += numbers[n];  /*Add numbers together*/ 
      n++; 
     } 
     /* Divide sum/count = average.*/ 
     printf("\n Average of floats = %f \n", sum/(count - 1)); 
    } 
    return 0; 
} 

/* Success Fri Sept 14 13:29 . That was hard work.*/ 
/* Always looks simple when working.*/ 
/* Next step is to use a function to work out the average.*/ 
/*Anonymous on July 04, 2012*/ 
/* http://www.careercup.com/question?id=14193663 */ 
+0

Dobra próba! Kilka sugestii dotyczących wydajności - staraj się unikać wielu realloc, które obejmują kopiowanie wszystkiego dookoła. Zamiast tego prześlij ponownie 2 lub 4 razy i zliczaj zarówno dostępną przestrzeń, jak i wykorzystaną przestrzeń. Również średnia może być obliczona w czasie wykonywania bez uprzedniego zapisywania czegokolwiek. – qdot

Powiązane problemy