2016-02-26 1 views
1

Я новичок, как в кодировке, так и на английском. Это мой код:Как читать строку неизвестного размера в C++

#include<iostream> 
#include<cstdio> 

using namespace std; 

int main() 
{ 
    int n=1; 
    char *a = new char[n],c=getchar(); 
    while((c!=EOF)||(c!='\n')) 
    { 
     a[n-1]=c; 
     c=getchar(); 
     n++; 
    } 
    cout << a; 
    delete[] a; 
    return 0; 
} 

Я изучаю динамическое распределение памяти. Проблема состоит в том, чтобы ввести строку, длина которой мне неизвестна. Моя идея читается строковым словом мое слово и останавливается, когда он достигает EOF или \ n. Не могли бы вы указать на ошибку? И еще один вопрос: мне сказали, что новый выбирает блок памяти указанного размера. Итак, что произойдет, если не будет достаточно большого блока? Спасибо за помощь!

+5

В C++ используется класс строки для этого. – Donnie

+2

Естественным способом в C++ было бы использование 'std :: string' и' getline' или '>>' для чтения в строку. В противном случае вам нужно будет перераспределять и копировать в более крупный массив. – crashmstr

+2

Вы конкретно пытаетесь не использовать стандартные библиотечные инструменты 'std :: string' и' getline'? –

ответ

3
#include <iostream> 
#include <string> 

int main() { 
    std::string line; 
    // first argument is the stream from whence the line comes. 
    // will read to newline or EOF 
    std::getline(std::cin, line); 
} 
+1

OP не может использовать строки (это назначение) и должен практиковаться в распределении динамической памяти, поэтому ... Боюсь, что ваш ответ (хотя и хороший) не очень полезен. –

+0

@Bob__ OP не указывал, что задавая вопрос. – erip

2

Прежде всего, нет никакой необходимости использовать char* и new char[n]. Вы можете использовать std::string.

Тогда вы должны спросить себя:

  1. Может строка содержит пробельные символы?
  2. Может ли строка охватывать несколько строк?
  3. Если он может охватывать несколько строк, сколько строк оно охватывает?

Если ответ на первый вопрос «Нет», вы можете использовать:

std::string s; 
cin >> s; 

Если ответ на первый вопрос «Да» и ответ на второй вопрос: «Нет ", тогда вы можете использовать:

std::string s; 
getline(cin, s); 

Если ответ на второй вопрос« Да », ответ становится более сложным.

Затем вам нужно найти ответы на другие вопросы?

  1. Является ли количество строк жестко закодированным?
  2. Если это не жестко закодировано, как программа получает этот номер от пользователя?

Основываясь на ответах на эти вопросы, ваш код будет отличаться.

3

[Я знаю, придерживаясь лучших практик и методов, доступных является «хорошим» , что нужно сделать, но OP должен знать, почему текущий код не работает и другие ответы здесь, кажется, не быть ответ]

Во-первых, для этого необходимо использовать класс строк C++.

Во-вторых, если вы задаетесь вопросом, почему ваш текущий код не работает, это потому, что:

я. Условие внутри пока неправильно. В нем говорится: «Выполните этот блок, если символ не \n, или это не конец файла». Поэтому, даже если вы нажмете enter (c is '\n'), этот блок все равно будет выполняться, потому что «c не EOF» и наоборот.

ii.Вы выделяете только 1 байт памяти на char*, чего явно недостаточно.

Это должно достаточно повторить то, что вы хотите, но память выделяется статична и строка должна быть ограничена,

int main() 
{ 
    int n=1; 
    char *a = new char[100],c=getchar(); 
    while(true) 
    { 
     if(c == '\n' || c == EOF){ 
      break; 
     } 
     a[n-1]=c; 
     c=getchar(); 
     n++; 
    } 
    cout << a; 
    delete[] a; 
    return 0; 
} 
1

Учитывая ограничение вашей задачи (не std::string, нет std::vector, динамическое распределение памяти) , Я постараюсь дать вам модифицированную, но рабочую версию вашего кода.

Моей идеей является прочитанное слово словом мое слово и остановка, когда он достигнет EOF или \ n. Не могли бы вы указать на ошибку?

Поскольку мольбднило указал (c!=EOF) || (c!='\n'), это всегда верно, поэтому ваша петля никогда не кончится.

Как вы заметили, ваш буфер длиной всего 1 символ, и вы не проверяете переполнение, кроме того, вы забыли добавить нулевой терминатор в конце его.

Ваш второй вопрос о том, что произойдет, когда new не может выделить достаточное количество памяти. Ну, это генерирует исключение, которое ваша программа должна поймать, чтобы управлять ситуацией, но самое лучшее (а не единственное на самом деле, может быть, самое легкое), которое вы можете сделать, это прекратить вашу программу.

Это пример того, как выполнить задание с учетом вышеуказанных ограничений:

#include <iostream> 

using namespace std; 

const int INITIAL_SIZE = 8; 

int main() { 
    // the following block of code could rise an exception 
    try 
    { 
     int n = 0; 
     char c; 

     // allocate some memory to store the null terminated array of chars 
     char *a = new char[INITIAL_SIZE]; 
     // what happens if new fails? It throws an exception of type std::bad_alloc 
     // so you better catch it 
     int allocated = INITIAL_SIZE; 

     // read a charachter from stdin. If EOF exit loop 
     while(cin.get(c)) 
     { 
      // If it's a newline or a carriage return stop 
      if('\n' == c || '\r' == c) 
       //^ note that ^^^ putting the literals first helps avoiding common 
       // error like using "=" instead of "==" in conditions 
       break; 

      a[n] = c; 

      // if the array is full it's time to reallocate it 
      if (n == allocated) 
      { 
       // There are alternatives, of course, but I don't know which library 
       // you are allowed to use, so I assume no one and BTW your compiler 
       // could be smart enough to recognize the pattern and optimize it 

       // allocate a bigger array 
       allocated *= 2; 
       char *b = new char[allocated]; 

       // copy the old one in the new one 
       for (int i = 0; i <= n; ++i) 
       { 
        b[i] = a[i]; 
       } 

       // release the memory handled by the old one... 
       delete[] a; 

       // but keep using the same pointer. Just remember not to delete b 
       // so that a allways points to allocated memory. 
       a = b; 
      } 
      // a new character has been succesfuly added 
      ++n; 
     } 

     // now before using a, we have to add the null terminator 
     a[n] = '\0'; 

     // note that a doesn't contain the '\n' 
     cout << a << '\n'; 

     delete[] a; 

     // normal program termination 
     return 0; 
    } 
    // If new fails to allocate memory a std::bad_alloc exception is thrown 
    catch (const exception &e) 
    { 
     cout << "Exception caught: " << e.what() << "\nProgram terminated.\n"; 
     return -1; 
    } 
}