Ошибка доступа Access на VC ++ - PullRequest
0 голосов
/ 19 марта 2012

Почему я получаю «Ошибка чтения нарушения доступа» в следующей программе:

Ошибка в цикле while для чтения файла.

#include <iostream>

class fileReader
{
public:
    FILE *fp;
    char** lines;
    fileReader()
    {
        fp = NULL;
    }
    fileReader(const char* path)
    {
        int i=0;
        fp = fopen(path,"r");
        while ( fgets(lines[i], 100, fp) )
            i++;
    }
};

int main(int argv, char** argc)
{
    const char* path = "D:\\PS4263-2.txt";
    fileReader *p = new fileReader(path);
    for (int i=0; i<2; i++)
        std::cout<<p->lines[i];
    return 0;
}

РЕДАКТИРОВАТЬ

Как указано в ответах, я изменил свой код на (ниже), но все еще получаю ту же ошибку.

#include <iostream>

class fileReader
{
public:
    FILE *fp;
    char** lines;
    fileReader()
    {
        fp = NULL;
    }
    fileReader(char* path)
    {
        int j=0;
        fp = fopen(path,"r");
        if (fp == NULL) 
            return;
        else 
        {
            lines = (char**) malloc(sizeof(char *)*56000);
            for (int i=0; i<56000; i++)
                lines[i] = (char*)malloc(sizeof(char)*1440);
            while ( fgets(lines[j], 1440, fp) )
                j++;
            fclose(fp);
        }
    }
};

int main(int argv, char** argc)
{
    char* path = "D:\\testfile.txt";
    fileReader *p = new fileReader(path);
    for (int i=0; i<2; i++)
        std::cout<<p->lines[i];
    return 0;
}

Ответы [ 3 ]

1 голос
/ 19 марта 2012

В ваших кодах много проблем:

  1. char** lines не выделено. Вам нужно выделить lines и lines[i].
  2. Вы никогда не проверяете, действительно ли файл открыт. Проверьте fp перед использованием.
  3. Вы забыли закрыть указатель файла в конце. Звоните fclose(fp).

РЕДАКТИРОВАТЬ:

Вы не освобождаете lines, lines[i] и p. Будьте осторожны, вы должны использовать free() для lines и lines[i] и delete для p.

1 голос
/ 19 марта 2012

Существует ряд проблем с этим кодом. Но прежде всего проблема в том, что вы пишете какой-то злой гибрид C / C ++. Выберите один из двух языков и используйте его.

Вот пересмотренная версия вашего кода:

#include <iostream>

class fileReader
{
public:
    FILE *fp;
    char** lines;
    fileReader() : fp(NULL) // initialization of members happens here
    {
        //fp = NULL; // anything here happens *after* initialization
        lines = new char*[100]; // let's just assume max 100 lines. We have to allocate space for them
        for (int i = 0; i < 100; ++i) {
            lines[i] = new char[100]; // allocate space for the contents of each individual line
        }
    }
    fileReader(const char* path)
    {
        lines = new char*[100]; // let's just assume max 100 lines. We have to allocate space for them
        for (int i = 0; i < 100; ++i) {
            lines[i] = new char[100]; // allocate space for the contents of each individual line
        }

        int i=0;
        fp = fopen(path,"r");
        while ( fgets(lines[i], 100, fp) )
            i++;
    }
    ~fileReader() {
        // deallocate and close our members:
        fclose(fp);
        for (int i = 0; i < 100; ++i) {
            delete[] lines[i]; // delete the contents of each line
        }
        delete[] lines; // delete the lines array
    }
};

int main(int argv, char** argc)
{
    const char* path = "D:\\PS4263-2.txt";
    fileReader p(path); // don't use new unless you really really have to
    for (int i=0; i<2; i++)
        std::cout<<p.lines[i];
    return 0;
}

Теперь, по крайней мере, это работает, , если каждая строка содержит менее 100 символов и , меньше 100 строк и файл существует и дюжина других условия, от которых мы действительно должны защищаться. В частности, мы тратим много усилий на управление памятью: выделение и освобождение места для всех данных строки.

Но мы можем сделать намного лучше с помощью нескольких изменений, если мы действительно начнем писать C ++.

#include <iostream> // we need this for the standard streams (cout)
#include <fstream> // we need proper C++ file streams too
#include <string> // C++ has strings. Don't waste your time on char pointers
#include <vector> // C++ has a dynamic array class. Don't use pointers as ad-hoc arrays

class fileReader
{
public:
    // FILE* fp; // no point in making this a class member, when it's only used in one function
    std::vector<std::string> lines; // use a vector of strings. Much easier to manage
    fileReader() // vectors are automatically initialized, no need to do anything
    {
    }
    fileReader(std::string path)
    {
        std::ifstream fp(path); // create an input file stream 
        std::string result; // store the contents of the current line here
        while (std::getline(fp, result)) {
                lines.push_back(result); // append the resulting line to the end of the vector
        }
    }
};

int main(int argv, char** argc)
{
    std::string path = "blah.txt";
    fileReader p(path); // don't use new unless you absolutely have to
    for (int i=0; i<2; i++)
        std::cout<<p.lines[i];
    return 0;
}

Обратите внимание, что нам больше не нужно управлять памятью массива. Векторы и строки автоматически убираются за собой, когда выходят из области видимости. И поскольку мы больше не используем new для выделения fileReader, он автоматически удаляется, когда it выходит из области видимости. Это фактически запускает цепную реакцию, когда его члены начинают очищаться после себя: поток файлов закрывается, векторы освобождают его память после того, как просят свои сохраненные строки очистить и закрыть. И вся программа сворачивается и закрывается без необходимости написания единой строки кода для ее обработки.

1 голос
/ 19 марта 2012
char** lines;

Никогда не было выделено никакой памяти!
Чтобы иметь возможность делать что-либо значимое с этим, вам нужно выделить достаточно памяти для хранения содержимого, которое вы намереваетесь хранить в нем.

Также в sidenote,

  • Вы никогда не освобождаете динамическую память, выделенную для p, вызывая delete p;, как только закончите с его использованием, это дает вам неопределенное поведение.
  • Выникогда не проверяйте возвращаемое значение стандартных библиотечных функций, вы всегда должны делать это.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...