views:

437

answers:

4
+3  Q: 

Bad Pointer? - C++

Hi there, I'm writing a string tokenization program for a homework assignment in C++, that uses pointers. However, when I run & debug it, it says that my pointer pStart, is invalid. I have a feeling that my problem resides in my param'ed constructor, I've included both the constructor and the object creation below.

I would appreciate it if you might tell me why it says that pStart is a bad pointer when I debug it.

Thanks!

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", ' ' );

Full stringtokenizer.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;
}

The function Next is supossed to return a pointer to the next word in the char array. It's currently not finished. :)

Full stringtokenizer.h:

#pragma once

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

Full 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;
+1  A: 

Change

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

to

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

A string literal is always a const char * const variable, and since C++ automatically casts a non const to const, it can't cast a const to non const.

You can also make different constructors, but I don't think you'll need it, as long as you just read the pArray string.

You could use something like this:

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;
}
Spidey
But now I get: `error C2440: '=' : cannot convert from 'const char *' to 'char *`
Alex
I'm reading in a char array by the way
Alex
Please, add more info them. You see, the string literal is CONSTANT, you can't alter it in any way. I think you are actually assigning it to another char*, you can't, you have to assign it to another const char *.I'll edit the answer to show you a little bit of the actual code as I'm thinking.
Spidey
+2  A: 

You can't modify pStart in your tokenizer, because a literal string in C and C++ is not modifiable, it has a type const char *. When you do the assignment

pStart = pArray;

in your constructor, pStart is now pointing to a non-modifiable memory. Most likely that is your problem. You will need to post more code if that's not the case.

Edit: After looking at your edit, looks like you have changed your code to use an array. That's good. I haven't looked at your code in too much detail, but there is at least one error:

while (pStart != NULL)

should be:

while (pStart != NULL && *pStart)

This is because you want to stop your loop when you hit the terminating '\0' in your string.

I am not sure why you're using C-style strings in C++. Is this a requirement in your homework?

Alok
Does it change anything if I'm using a char array?
Alex
char array where? If `pStart` is a char array, the assignment wouldn't even compile: you can't assign to array in C++. Post minimal complete code please.
Alok
+1  A: 

Change pStart in the StringTokenizer class from char* to const char*, and make the same change to the constructor.

Spidey
Thank you! Major help on the project!
Alex
A: 

In my opinion, you should change the constructor and destructor of StringTokenizer:

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

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

Now you can use pStart in the way you are using it: modifying the string, putting zeroes in order to mark words, etc. You do only need to add a "char * str" private attribute to StringTokenizer.

The trick here is that you are creating your own copy of the string, thus you can manipulate anyway you want, provided you free it in the destructor. The only downside is that you need memory in order to store the copy (so you need twice memory for each string).

The reason your solution didn't work is that literals are or can be stored in read-only memory, so they are correctly marked as const char*, being "impossible" to write to them.

Baltasarq