Trouble with strtok and string formatting

Hi everyone, I am a self-taught programmer trying to write code to print a message such that no word will be split up over the edge of the screen; a form of text wrap in C++. I've been trying to use strtok() to capture each word, but with the code below I'm receiving the following run-time error message...

Unhandled exception at 0x5cf13b60 (msvcr100d.dll) in Demo.exe: 0xC0000005: Access violation writing location 0x012fae4c.


Any idea on what the problem is? I've done some google searches to read up more on strtok, and as far as I know, my use of strtok() is correct. But, obviously, I'm missing something. Thanks in advance for the help.

Variables:
q[] is a *char array that holds a paragraph in each cell
word[] is a *char array that intends to hold each word of the selected paragraph
N is a random int value to choose from a variety of messages to display
letters is an integer value (starting at 73) that represents the total number of character spaces across the C++ display console

1
2
3
4
5
6
7
8
9
10
11
12
13
	word[ i ] = strtok( q[ N ], " " );
	while ( word[ i ] != NULL ) {
		if ( letters - strlen( word[ i ] ) >= 1 ) {
			cout << word[ i ] << " ";
			letters -= strlen( word[ i ] );
		}
		else {
			cout << endl << word[ i ] << " ";
			letters = 73 - strlen( word[ i ] );
		}

		i++;
	}
closed account (zb0S216C)
Access violations are a result of writing to memory that isn't yours; that is, memory that hasn't been allocated. By looking at the code you provided, it seems as though the bounds of an array have been violated. In Layman's terms, you're over-stepping the boundaries of an array.

Make sure the location is valid before reading/writing to it.

Wazzak
Last edited on
Thanks for the quick reply Wazzak. The concept makes sense, but I haven't yet learned about data allocation. I've declared the array earlier in the code, and it should be large enough to hold all the data of each given array. Here's the function in its entirety:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void printQuote( char *q[], int qUse[] )
{
	int N = rand() % quoteNumber;
	int i = 0;
	int letters = 73;
	char g;
	char *word[ 299 ];

	cout << endl << endl << q[ i++ ] << endl << endl;

	if ( qUse[ N ] == 1 )
		N = rand() % quoteNumber;

	cout << "The contents of this quote will help you on your way!" << endl << endl;
	
	word[ i ] = strtok( q[ N ], " " );
	while ( word[ i ] != NULL ) {
		if ( letters - strlen( word[ i ] ) >= 1 ) {
			cout << word[ i ] << " ";
			letters -= strlen( word[ i ] );
		}
		else {
			cout << endl << word[ i ] << " ";
			letters = 73 - strlen( word[ i ] );
		}

		i++;
	}

	qUse[ N ] = 1;

	cout << "Enter 'c' to continue...";
	cin >> g;

	clearScreen();
}
Is there some other step I need to include to allocate more space for the array?
It may help knowing what q is. If it's something like char* q[] = {"bad", "idea"};, then strtok cannot be used with its members (string literals are read-only)
Hey Cubbi, q[] is defined as...

char *q[ 350 ] = { "This is the first sentence.", "And this is the second.", "And so on.", "For three hundred some more sentences. And some are paragraphs." };
closed account (zb0S216C)
There's a huge problem here. Your word array is an array of pointers to char's. Each pointer within that array must be given memory dynamically, or be pointed to another array or char. For instance, consider this:

1
2
3
4
5
6
7
8
char *pWord[2];

// Dynamically allocate memory:
pWord[0] = (char*)calloc(51, sizeof(char));

// Pointing to another array:
char String[] = "This is a string";
pWord[1] = String;

The DMA (Dynamic memory allocation) allocates a block of 51 chars.

Wazzak
Hmmm, ok, I think I understand the concept behind what you're saying, although some of the code you wrote I don't understand (namely "(char*)calloc(51, sizeof(char));). So what will I need to do to fix this? If DMA allocates space for 51 chars for each member of word[], then that shouldn't be a problem unless I have a word more than 51 letters long, right?

Earlier in the development of the program, before I tried this text-wrap functionality, the q[] array of quotations (each element is a pointer to a quotation) was working fine. It wasn't until I tried breaking up each quotation into words with strtok that the issue arose.

Or, is the problem that I have to individually assign memory space to each element of word[] in order for it to work? Will a for loop moving through each element of word[] and allocating space specfically with the calloc() line fix this?
Last edited on
I just tried adding the following, to no avail:
1
2
for ( int j = 0; j < 299; j++ )
		word[ j ] = (char*)calloc(20, sizeof(char));
dpan wrote:
q[] is defined as...

char *q[ 350 ] = { "This is the first sentence.", "And this is the second.", "And so on.", "For three hundred some more sentences. And some are paragraphs." };

There's your problem. You cannot use strtok() with a string literal. Modern compilers (sufficiently C++11-conformant) won't even allow that declaration to compile because string literals are arrays of const char and you're creating char*'s ("pointers to non-const char") to point to const data.

In any case, you've mentioned C++ in your original post, in C++ strings are objects of type string, and can be parsed in a multitude of ways using streams or string's own functions.
Last edited on
Ok, so I can't use strtok() since that function modifies the string. The possible solutions you mentioned I'm not familiar with. Any place you can point me to to learn more about these things? I'm trying to finish this program by Christmas, since it's a gift to someone.
dpan wrote:
Any place you can point me to to learn more about these things?

http://www.cplusplus.com/reference/string/string/
http://www.cplusplus.com/reference/iostream/istringstream/
http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c
But if you're not familiar with strings, it's a huge topic to take in before Christmas.
Last edited on
Hey everyone, I've got it all figured out. I'm sure it's not efficient and I'm pretty sure it's not orthodox, but it works, and that's all that matters for this gift (inb4 comment on standing on the shoulders of giants). Cubbi, those links you gave were crucial. I didn't understand a lot of it, but enough that I could experiment with the functions until something worked.

Thanks everyone for the help. Here's the final code for the function for those who are curious. Merry Christmas and happy holidays cplusplus.com.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
	int N = rand() % quoteNumber;
	int i = 0;
	int letters = 73;
	int currentPos = 0;
	int lastPos = -1;
	int firstPos = 0;
	char g;
	string str;
	char stringy[ 500 ];
	char word[ 30 ];
	int wordLength;
	size_t k;
	
	if ( qUse[ N ] == 1 )
		N = rand() % quoteNumber;
	str = q[ N ];

	for ( k = 0; k < str.length(); k++ )
		stringy[ k ] = str.at( k );
	stringy[ k ] = '\0';
	
	cout << "The contents of this quote will help you on your way!" << endl << endl;
	
	do {
		i = 0;
		for ( firstPos = currentPos = lastPos + 1; stringy[ currentPos ] != ' ' && stringy[ currentPos ] != '\0'; currentPos++ )
			word[ i++ ] = stringy[ currentPos ];
		word[ i ] = ' ';

		lastPos = currentPos;
		wordLength = lastPos - firstPos + 1;
	
			if ( letters - wordLength >= 1 ) {
				for ( int m = 0; m < wordLength; m++ )
					cout << word[ m ];
				letters -= wordLength;
			}
			else {
				cout << endl;
				for ( int m = 0; m < wordLength; m++ )
					cout << word[ m ];
				letters = 73 - wordLength;
			}
	} while ( stringy[ currentPos ] != '\0' );

	qUse[ N ] = 1;

	cout << "\n\nEnter 'c' to continue... ";
	cin >> g;
	cin.clear();
	cin.ignore(numeric_limits<streamsize>::max(), '\n');

	clearScreen();
Topic archived. No new replies allowed.