Плохой указатель? - C ++ - PullRequest
       13

Плохой указатель? - C ++

3 голосов
/ 06 февраля 2010

Я пишу программу токенизации строк для домашнего задания на C ++, в которой используются указатели. Однако, когда я запускаю и отлаживаю его, он говорит, что мой указатель pStart недействителен. У меня такое ощущение, что моя проблема заключается в моем param'ed конструкторе, я включил и конструктор, и создание объекта ниже.

Буду признателен, если вы скажете мне, почему он говорит, что pStart является плохим указателем, когда я отлаживаю его.

Спасибо!

StringTokenizer::StringTokenizer(char* pArray, char d)
{
pStart = pArray;
delim = d;
}

// create a tokenizer object, pass in the char array
// and a space character for the delimiter
StringTokenizer tk( "A test char array", ' ' );

Полная строкаtokenizer.cpp:

#include "stringtokenizer.h"
#include <iostream>
using namespace std;

StringTokenizer::StringTokenizer(void)
{
pStart = NULL;
delim = 'n';
}

StringTokenizer::StringTokenizer(const char* pArray, char d)
{
pStart = pArray;
delim = d;
}

char* StringTokenizer::Next(void)
{
char* pNextWord = NULL;

while (pStart != NULL)
{
    if (*pStart == delim)
    {
        *pStart = '\0';
        pStart++;
        pNextWord = pStart;

        return pNextWord;
    }
    else
    {
        pStart++;
    }
}
    return pNextWord;
}

Функция Next предназначена для возврата указателя на следующее слово в массиве char. Это в настоящее время не закончено. :)

Полная строкаtokenizer.h:

#pragma once

class StringTokenizer
{
public:
StringTokenizer(void);
StringTokenizer(const char*, char);
char* Next(void);
~StringTokenizer(void);
private:
char* pStart;
char delim;
};

Полный main.cpp:

const int CHAR_ARRAY_CAPACITY = 128;
const int CHAR_ARRAY_CAPCITY_MINUS_ONE = 127;

// create a place to hold the user's input
// and a char pointer to use with the next( ) function
char words[CHAR_ARRAY_CAPACITY];
char* nextWord;

cout << "\nString Tokenizer Project";
cout << "\nyour name\n\n";
cout << "Enter in a short string of words:";
cin.getline ( words, CHAR_ARRAY_CAPCITY_MINUS_ONE );

// create a tokenizer object, pass in the char array
// and a space character for the delimiter
StringTokenizer tk( words, ' ' );

// this loop will display the tokens
while ( ( nextWord = tk.Next ( ) ) != NULL )
{
    cout << nextWord << endl;
}


system("PAUSE");
return 0;

Ответы [ 4 ]

3 голосов
/ 06 февраля 2010

Вы не можете изменить pStart в вашем токенизаторе, потому что литеральная строка в C и C ++ не модифицируется, она имеет тип const char *. Когда вы делаете назначение

pStart = pArray;

в вашем конструкторе, pStart теперь указывает на неизменяемую память. Скорее всего, это ваша проблема. Вам нужно будет разместить больше кода, если это не так.

Редактировать : После просмотра вашей правки похоже, что вы изменили свой код для использования массива. Это хорошо. Я не слишком подробно рассмотрел ваш код, но есть по крайней мере одна ошибка:

while (pStart != NULL)

должно быть:

while (pStart != NULL && *pStart)

Это потому, что вы хотите остановить цикл, когда нажимаете на завершающий '\0' в вашей строке.

Я не уверен, почему вы используете строки в стиле C в C ++. Это требование в вашей домашней работе?

1 голос
/ 06 февраля 2010

Изменение

StringTokenizer::StringTokenizer(char* pArray, char d)

до

StringTokenizer::StringTokenizer(const char * pArray, char d)

Строковый литерал всегда является переменной const char * const, и, поскольку C ++ автоматически преобразует не const в const, он не может преобразовать const в не const.

Вы также можете создавать различные конструкторы, но я не думаю, что вам это понадобится, если вы только прочитали строку pArray.

Вы можете использовать что-то вроде этого:

TokenList& StringTokenizer::StringTokenizer(const char* pArray, char d){
  TokenList lst();
  size_t i=0;
  char buffer[100]; //hardcoded limit, just an example, you should make it grow dinamically, or just use a std::string
  while((*pArray)){
    if(*pArray == d){
      buffer[i] = 0; //string ending character, 0 = '\0';
      lst.add(buffer);
      i=0;
    }
    pArray++;
  }
  //Last token in the input string won't be ended by the separator, but with a '\0'.
  buffer[i] = 0;
  lst.add(buffer);

  return lst;
}
0 голосов
/ 06 февраля 2010

На мой взгляд, вы должны изменить конструктор и деструктор StringTokenizer:

StringTokenizer::StringTokenizer(char* pArray, char d)
{
    pStart = str = strdup( pArray );
    delim = d;
}

StringTokenizer::~StringTokenizer(char* pArray, char d)
{
    free( str );
}

Теперь вы можете использовать pStart так, как вы его используете: изменение строки, установка нулей для маркировки слов и т. Д. Вам нужно только добавить закрытый атрибут char * str в StringTokenizer.

Хитрость в том, что вы создаете свою собственную копию строки, поэтому вы можете манипулировать любым способом, каким хотите, при условии, что вы освободите ее в деструкторе. Единственным недостатком является то, что вам требуется память для хранения копии (поэтому вам нужно дважды памяти для каждой строки).

Причина, по которой ваше решение не сработало, заключается в том, что литералы хранятся или могут храниться в постоянном запоминающем устройстве, поэтому они правильно помечены как const char *, что делает их "невозможными" для записи.

0 голосов
/ 06 февраля 2010

Измените pStart в классе StringTokenizer с char * на const char * и внесите то же изменение в конструктор.

...