Access violation with pointers? - C ++

I wrote a simple program to string tokenization using pointers for a recent school project. However, I am having problems with my StringTokenizer::Next() method, which when called should return a pointer to the first letter of the next word in the char array. I have no compile-time errors, but I get a runtime error that reads:

 Unhandled exception at 0x012c240f in Project 5.exe: 0xC0000005: Access violation reading location 0x002b0000. 

Currently, the program tokenizes the char array, but then stops, and this error appears. I feel this is due to the NULL check that I am doing in my Next() method.

So how can I fix this?

Also, if you notice anything that I could do more efficiently or with better practice, let me know.

Thanks!!


StringTokenizer.h:

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

StringTokenizer.cpp:

 #include "stringtokenizer.h" #include <iostream> using namespace std; StringTokenizer::StringTokenizer(void) { pStart = NULL; pNextWord = NULL; delim = 'n'; } StringTokenizer::StringTokenizer(char* const pArray, char d) { pStart = pArray; delim = d; } char* StringTokenizer::Next(void) { pNextWord = pStart; if (pStart == NULL) { return NULL; } while (*pStart != delim) // access violation error here { pStart++; } if (pStart == NULL) { return NULL; } *pStart = '\0'; // sometimes the access violation error occurs here pStart++; return pNextWord; } StringTokenizer::~StringTokenizer(void) { delete pStart; delete pNextWord; } 

main.cpp:

 // The PrintHeader function prints out my // student info in header form // Parameters - none // Pre-conditions - none // Post-conditions - none // Returns - void void PrintHeader(); int main ( ) { const int CHAR_ARRAY_CAPACITY = 128; const int CHAR_ARRAY_CAPCITY_MINUS_ONE = 127; // create a place to hold the user input // and a char pointer to use with the next( ) function char words[CHAR_ARRAY_CAPACITY]; char* nextWord; PrintHeader(); 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; } 


EDIT:

Ok, now the program works fine as long as the delimiter is space. But if I pass him `/ 'as delim, he will again encounter an access violation error. Any ideas?

Function that works with spaces:

 char* StringTokenizer::Next(void) { pNextWord = pStart; if (*pStart == '\0') { return NULL; } while (*pStart != delim) { pStart++; } if (*pStart = '\0') { return NULL; } *pStart = '\0'; pStart++; return pNextWord; } 
0
source share
4 answers

This answer is based on an edited question and various comments / observations in other answers ...

First, what are the possible states for pStart when calling Next ()?

  • pStart - NULL (default constructor or otherwise set to NULL)
  • * pStart is '\ 0' (empty line at the end of the line)
  • * pStart - delim (empty string in the adjacent delimiter)
  • * pStart is something else (a token is not an empty string)

At this point, we only need to worry about the first option. Therefore, I would use the original "if" here:

 if (pStart == NULL) { return NULL; } 

Why don't we need to worry about cases 2 or 3? You probably want to treat adjacent delimiters as having a token with an empty string between them, including at the beginning and end of the line. (If not, tune in.) The while loop will handle this for us if you also add the "\ 0" check (necessary independently):

 while (*pStart != delim && *pStart != '\0') 

After a while loop, you have to be careful. What are the possible conditions now?

  • * pStart is '\ 0' (end of token at end of line)
  • * pStart - delim (end of token on the next delimiter)

Note that pStart cannot be NULL here.

You need to return pNextWord (current token) for both of these conditions so that you do not discard the last token (i.e. when * pStart is '\ 0'). The code correctly processes register 2, but not case 1 (the source code dangerously increases by pStart for "\ 0", the new code returns NULL). In addition, it is important that reset pStart for case 1 is correct, so the next call to Next () returns NULL. I will leave the exact code as an exercise for the reader, as this is homework in the end;)

This is a good exercise to describe the possible data states in the entire function, in order to determine the correct action for each state, similar to the formal definition of basic cases compared to recursive cases for recursive functions.

Finally, I noticed that you delete calls to both pStart and pNextWord in your destructor. First, to remove arrays, you need to use delete [] ptr; (i.e. remove the array). Secondly, you will not delete both pStart and pNextWord, because pNextWord points to the pStart array. Thirdly, pStart no longer points to the beginning of memory, so you need a separate element to store the initial launch to call delete [] . Finally, these arrays are allocated on the stack, not on the heap (i.e., using char var[] , not char* var = new char[] ), and therefore they should not be deleted. Therefore, you should simply use an empty destructor.

Another good tip is to count the number of calls new and delete ; should be the same amount of each. In this case, you have zero new calls and two delete calls, which indicates a serious problem. If it were the other way around, it would mean a memory leak.

+1
source

Access violation (or “segmentation error” on some operating systems) means that you tried to read or write a position in memory that you never allocated.

Consider the while loop in Next ():

 while (*pStart != delim) // access violation error here { pStart++; } 

Let's say the string is "blah\0" . Note that I have included trailing zero. Now ask yourself: how does this loop know to stop when it reaches the end of the line?

More importantly: what happens to *pStart if the loop does not stop at the end of the line?

+4
source

Inside :: Next you need to check the delim character, but you also need to check the end of the buffer (which I assume is denoted by \ 0).

 while (*pStart != '\0' && *pStart != delim) // access violation error here { pStart++; } 

And I think these tests are in :: Next

 if (pStart == NULL) { return NULL; } 

It must be this.

 if (*pStart == '\0') { return NULL; } 

That is, you should check for the Nul character, not the null pointer. It is unclear whether you plan to detect these uninitialized pointer pStart or the end of the buffer.

+1
source

Access violation usually means a bad pointer.

In this case, the most likely cause ends before you find the separator.

0
source

Source: https://habr.com/ru/post/1300585/


All Articles