2017-02-09 24 views
-2

The error messageВвод из текстового файла в массив полукокса * [9]

У меня есть файл с 9 слов, и я должен хранить каждое слово в массив символов 9 указателей, но я постоянно получаю сообщение об ошибке. Я не могу использовать векторы!

#include <iostream> 
#include <fstream> 


using namespace std; 


int main() 
{ 
    char *words[9]; 
    ifstream inStream; 
    inStream.open("sentence.txt"); 
    if (inStream.fail()) 
    { 
     cout << "Input file opening failed.\n"; 
     exit(1); 
    } 

    for (int i = 0; i < 10; i++) 
    { 
     inStream >> words[i]; 
    } 

     inStream.close(); 

    return 0; 
} 
+1

[с использованием патезрасе плохо] (http://stackoverflow.com/questions/4043930/is-using-namespace-like-bad) - также почему вы не используете 'std :: string'? –

+1

И сообщение _error_ есть ??? –

+0

Также проверьте, открыли ли вы файл –

ответ

2

Декларация

char *words[9]; 

объявляет необработанный массив указателей. Этот массив не инициализирован, поэтому указатели имеют неопределенные значения. Использование любого из них было бы Неопределенным Поведением.

Вместо этого вы хотите

vector<string> words; 

vector где находится std::vector из заголовка <vector> и string является std::string из заголовка <string>.

Используйте функцию члена push_back, чтобы добавить строки в конец вектора.

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

Такой подход дает код (экспромтом, оговорке ...)

#include <fstream> 
#include <iostream> 
#include <vector> 
#include <string> 
using namespace std; 

int main() 
{ 
    vector<string> words; 
    ifstream inStream; 
    inStream.open("sentence.txt"); 

    for (int i = 0; i < 10; i++) 
    { 
     string word; 
     if(inStream >> word) 
      words.push_back(word); 
    } 
    inStream.close(); 
} 

Если вы не можете использовать std::string и std::vector, то вам необходимо инициализировать массив указателей, и сделать что вы больше не читаете в буферах, чем есть место.

Основная проблема заключается в том, что >> небезопасен для чтения в необработанный массив, заданный указателем. Он не знает, насколько велик массив. Это может привести к переполнению буфера с тяжелыми последствиями.

И поэтому это становится немного сложнее, но это может выглядеть следующим образом:

#include <ctype.h>   // isspace 
#include <fstream> 
#include <iostream> 
#include <locale.h>   // setlocale, LC_ALL 
#include <stdlib.h>   // EXIT_FAILURE 
using namespace std; 

void fail(char const* const message) 
{ 
    cerr << "! " << message << "\n"; 
    exit(EXIT_FAILURE); 
} 

void readWordFrom(istream& stream, char* const p_buffer, int const buffer_size) 
{ 
    int charCode; 

    // Skip whitespace: 
    while((charCode = stream.get()) != EOF and isspace(charCode)) {} 

    int n_read = 0; 
    char* p = p_buffer; 
    while(n_read < buffer_size - 1 and charCode != EOF and not isspace(charCode)) 
    { 
     *p = charCode; ++p; 
     ++n_read; 
     charCode = stream.get(); 
    } 
    *p = '\0';  // Terminating null-byte. 

    if(charCode != EOF) 
    { 
     stream.putback(charCode); 
     if(not isspace(charCode)) 
     { 
      assert(n_read == buffer_size - 1); // We exceeded buffer size. 
      stream.setstate(ios::failbit); 
     } 
    } 
} 

int main() 
{ 
    static int const n_words   = 9; 
    static int const max_word_length = 80; 
    static int const buffer_size  = max_word_length + 1; // For end byte. 

    char *words[n_words]; 
    for(auto& p_word : words) { p_word = new char[buffer_size]; } 

    ifstream inStream{ "sentence.txt" }; 
    if(inStream.fail()) { fail("Input file opening failed."); } 

    setlocale(LC_ALL, "");   // Pedantically necessary for `isspace`. 
    for(auto const p_word : words) 
    { 
     readWordFrom(inStream, p_word, buffer_size); 
     if(inStream.fail()) { fail("Reading a word failed."); } 
    } 

    for(auto const p_word : words) { cout << p_word << "\n"; } 

    for(auto const p_word : words) { delete[] p_word; } 
} 
+0

Возможно, стоит упомянуть не закрывать файл в цикле, а также проверить, что файл открыт. Это добавило бы ответа –

+0

@EdHeal: Спасибо. Но сначала у меня есть горячий картофель. На духовке. :) –

+0

Я не могу использовать векторы для этого назначения –

1

Вы никогда не выделять какую-либо памяти для ваших char* указателей хранится в массиве.

идиоматических способ писать C++ код будет:

#include <iostream> 
#include <fstream> 
#include <vector> 

int main() { 
    std::vector<std::string> words(9); 
    std::ifstream inStream; 
    inStream.open("sentence.txt"); 

    for (int i = 0; inStream && i < 9; i++) { 
     inStream >> words[i]; 
    } 
} 

inStream.close() не является необходимым, и даже неправильно внутри цикла. std::istream будет автоматически закрыт, как только переменная выходит за пределы области видимости.

+0

Возможно, проверьте, был ли файл открыт, помогло бы –

+0

@EdHeal Добавлено условие ;-) –

1

Есть несколько проблем с кодом.

знак * слова [9]; Это выделяет пространство для 9 указателей, а не девяти строк. Поскольку вы не знаете, насколько велики строки, у вас есть два варианта. Вы можете «угадать», сколько вам потребуется, и ограничить ввод соответственно, или вы можете использовать динамическое распределение памяти (malloc или new), чтобы создать пространство, необходимое для хранения строк. Динамическая память будет моим выбором.

для (int i = 0; i < 10; i ++) Этот цикл будет выполняться словами [0] через слова [9]. Однако нет слов [9] (это будет десятое слово), чтобы вы перезаписали память, которую вы не присвоили

inStream >> words [i]; Это отправит ваш поток ввода в память, который вы не «владеете». Вы должны выделить пространство для слов, чтобы жить до их захвата из входного потока. Чтобы сделать это правильно, вам нужно знать, сколько места потребуется каждому слову, чтобы вы могли выделить его.

вы могли бы попробовать что-то вроде этого:

int main() 
{ 
    char *words[9]; 
    char tempInput[256]; // space to capture the input, up to a maximum size of 256 chars 
    ifstream inStream; 
    inStream.open("sentence.txt"); 
    if (inStream.fail()) 
    { 
     cout << "Input file opening failed.\n"; 
     exit(1); 
    } 

    for (int i = 0; i < 9; i++) 
    { 
     //Clear the input buffer 
     memset(tempInput, 0, 256); 

     //Capture the next word 
     inStream >> tempInput; 

     //allocate space to save the word 
     words[i] = new char(strlen(tempInput)); 

     //Copy the word to its final location 
     strcpy(words[i], tempInput) 
    } 

    inStream.close(); 

    return 0; 
} 
+0

как бы выделить память для 9 указателей? –

+0

Распределение памяти @BrendaGonzalez выполняется оператором 'new'. Читайте об этом в своей любимой ссылке на C++. –