Constructor not working as intended - c++

I am trying to get this constructor to do these set of things:
This constructor tries to open the file whose name is passed
to it in filename. If file opens successfully, calls function
getFileSize to determine how many bytes should be allocated
for the message. Allocates space for message and reads the
content from the file into it. Closes the file at the end.
Member variable length should be set to the file size.
If file cannot be found, length should be set to zero.
I am having trouble currently, when I try to run my program I get an error as it is not even reading my file and having trouble not understanding the problem. Any help would be appreciated thanks.
Constructor:
Message::Message(std::string filename) {
fstream fin(filename);
if (fin.fail())
{
cout << "failed";
}
else {
length = getFileSize(fin);
message = new char[length];
fin.getline(message, length); {
fin >> message;
}
}
fin.close();
}
.h File:
#ifndef MESSAGE_H_
#define MESSAGE_H_
#include <fstream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
class Message
{
private:
char *message; // holds the message
int length; // holds the the message length
static const short ALPHABET_SIZE = 26;
char code[ALPHABET_SIZE]; // holds the cypher alphabet
// iztohndbeqrkglmacsvwfuypjx
// ex: an 'a' in the original message should be converted to 'i', 'b' should be converted to 'z' and so forth
// returns the input file size in bytes
std::streamsize getFileSize(std::fstream &file) const
{
std::streamsize fsize = 0;
file.seekg(0, std::ios::end);
fsize = file.tellg();
file.seekg(0, std::ios::beg); // moves file pointer back to the beginning
return fsize;
}
public:
Message(std::string filename);
// The destructor frees the space allocated to message
virtual ~Message();
// Decodes the message
void decode();
// Capitalizes first letter in each sentence
void fixCapitalization();
// Prints the content of message on the screen
void dump() const;
// Returns true if the message is empty
bool isEmpty() const;
};
Here are my files:
OBJECT.CPP:
#include "Message.h"
using namespace std;
Message::Message(std::string filename) {
fstream fin(filename);
if (fin.fail())
{
cout << "failed";
}
else {
length = getFileSize(fin);
message = new char[length];
fin.getline(message, length); {
fin >> message;
}
}
fin.close();
}
Message::~Message()
{
//dtor
}
void Message::decode() {
int offset;
strcpy(code, "iztohndbeqrkglmacsvwfuypjx");
for (int i = 0; i < strlen(message); i++) {
if (message[i] == ' ') continue;
if (message[i] == ',') continue;
if (message[i] == '.') continue;
offset = int(message[i] - 'a');
message[i] = code[offset];
}
}
void Message::fixCapitalization() {
for (int i = 0; i < strlen(message); i++) {
if (message[0] != ' ' || message[0] != ',') {
message[0] = toupper(message[0]);
}
if (message[i] == '.' || message[i] == '?' || message[i] == ',') {
message[i + 2] = toupper(message[i + 2]);
}
}
}
void Message::dump() const {
for (int i = 0; i < strlen(message); i++) {
cout << message[i];
}
}
bool Message::isEmpty() const {
if (length == 0) {
return true;
}
else {
return false;
}
}
.H file:
/*
* Message.h
*
* Created on: Dec 11, 2016
* Author: hellenpacheco
*/
#ifndef MESSAGE_H_
#define MESSAGE_H_
#include <fstream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
class Message
{
private:
char *message; // holds the message
int length; // holds the the message length
static const short ALPHABET_SIZE = 26;
char code[ALPHABET_SIZE]; // holds the cypher alphabet
// iztohndbeqrkglmacsvwfuypjx
// ex: an 'a' in the original message should be converted to 'i', 'b' should be converted to 'z' and so forth
// returns the input file size in bytes
std::streamsize getFileSize(std::fstream &file) const
{
std::streamsize fsize = 0;
file.seekg(0, std::ios::end);
fsize = file.tellg();
file.seekg(0, std::ios::beg); // moves file pointer back to the beginning
return fsize;
}
public:
/*
* This constructor tries to open the file whose name is passed
* to it in filename. If file opens successfully, calls function
* getFileSize to determine how many bytes should be allocated
* for the message. Allocates space for message and reads the
* content from the file into it. Closes the file at the end.
* Member variable length should be set to the file size.
* If file cannot be found, length should be set to zero.
*/
Message(std::string filename);
// The destructor frees the space allocated to message
virtual ~Message();
// Decodes the message
void decode();
// Capitalizes first letter in each sentence
void fixCapitalization();
// Prints the content of message on the screen
void dump() const;
// Returns true if the message is empty
bool isEmpty() const;
};
#endif /* MESSAGE_H_ */
MAIN.CPP:
#include <iostream>
#include <stdlib.h>
#include <fstream>
#include "Message.h"
using namespace std;
int main()
{
// create a message object with the content of Encrypted.txt
Message m("Encrypted.txt");
if (m.isEmpty())
{
cout << "Could not read message";
return EXIT_FAILURE;
}
cout << "Original message: " << std::endl;
m.dump();
cout << std::endl << std::endl;
m.decode();
m.fixCapitalization();
cout << "Decoded message: " << std::endl;
m.dump();
cout << std::endl << std::endl;
return EXIT_SUCCESS;
}
The following file is the .txt file I am trying to open and "decode" and is all on 1 line:
ifqkwxcadf ar cei fpoi masif cd cei xkdqirr du pxxnwafm pf pnmdkaceo cd p oirrpmi, teaqe rqkpohnir cei gpcp af ac-oplafm ac sikw gauuaqvnc pfg caoi qdfrvoafm, au fdc xkpqcaqpnnw aoxdrrahni, cd gigvqi cei dkamafpn masif dfnw cei ifqdgig gpcp. afxvcr cd cei pnmdkaceo cwxaqpnnw afsdnsi pggacadfpn riqkic gpcp qpnnig liwr, teaqe xkisifcr cei oirrpmi ukdo hiafm giqdgig-isif au cei pnmdkaceo ar xvhnaqnw lfdtf.

Problems with
message = new char[length];
fin.getline (message, length); {
fin >> message;
}
getline will stop if a newline character is encountered.
The fin >> message; line will overwrite what was read in getline.
The { and } don't make sense at all. They are not problems per se but they lead me to think that you are not clear on what you are trying to do.
I would change those lines to
message = new char[length + 1]; // Add an extra character if
// message is supposed to be null
// terminated.
fine.read(message, length);
message[length] = '\0';

Related

ifstream read reading random char for the whole stream

I'm trying to implement the function from listing 5.1 here
but when copying into a buffer with read from a file I just get the same character (Í) for the whole array, where string.txt is a copy and paste from the previous link content.
Here is my code:
#include <iostream>
#include <fstream>
#include <string>
#include <cinttypes>
#include <cstdio>
#include <cstring>
const int block_size = 0x4000; //16KB
int search(char* buffer, int searchLength, char* stringToSearch, int stringToSearchLength) {
char * potentialMatch;
while (searchLength) {
potentialMatch = reinterpret_cast<char *>(memchr(buffer, *stringToSearch, searchLength));
if (potentialMatch == NULL)
break;
if (stringToSearchLength == 1) {
return 1;
} else {
if (!memcmp(potentialMatch + 1, stringToSearch + 1, stringToSearchLength - 1))
return 1;
}
searchLength -= potentialMatch - buffer + 1;
buffer = potentialMatch + 1;
}
return 0;
}
int main(int argc, char* argv[]) {
char *toSearch = "Interpreting Where";
int done = 0;
int found = 0;
char *buffer;
int64_t fileSizeLeft = 0;
std::ifstream myFile("string.txt");
if (!myFile.fail()) {
buffer = new char[block_size];
myFile.seekg(0, std::ios::end); //Get file's size
fileSizeLeft = myFile.tellg();
} else {
std::cout << "Cannot open file" << std::endl;
return 1;
}
int toSearchLength = strlen(toSearch);
int stringLeft = toSearchLength - 1;
int first_time = 1;
while (!done && fileSizeLeft > toSearchLength) {
if (first_time) {
myFile.read(buffer, block_size);
found = search(buffer, block_size, toSearch, toSearchLength);
} else {
memcpy(buffer, buffer + stringLeft, stringLeft);
myFile.read(buffer+stringLeft, fileSizeLeft-stringLeft);
found = search(buffer, block_size, toSearch, toSearchLength);
}
fileSizeLeft = fileSizeLeft - block_size;
first_time = 0;
}
if (found) {
std::cout << "String found" << std::endl;
} else {
std::cout << "String not found" << std::endl;
}
myFile.close();
delete[] buffer;
return 0;
}
I hope you can help me see what I'm doing wrong, thanks!
You are setting myFile's position to ios_base::end with seekg:
myFile.seekg(0, ios::end);
Then trying to read from it:
myFile.read(buffer, block_size);
Clearly no data will be read since myFile is already at ios_base::end. And you'll be reading whatever uninitialized data that was already in buffer
What you probably intended to do was to set your myFile position back to the beginning by doing this before reading:
myFile.seekg(0, ios::beg);

OpenSSL SHA256 Wrong result

I have following piece of code that is supposed to calculate the SHA256 of a file. I am reading the file chunk by chunk and using EVP_DigestUpdate for the chunk. When I test the code with the file that has content
Test Message
Hello World
in Windows, it gives me SHA256 value of 97b2bc0cd1c3849436c6532d9c8de85456e1ce926d1e872a1e9b76a33183655f but the value is supposed to be 318b20b83a6730b928c46163a2a1cefee4466132731c95c39613acb547ccb715, which can be verified here too.
Here is the code:
#include <openssl\evp.h>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdio>
const int MAX_BUFFER_SIZE = 1024;
std::string FileChecksum(std::string, std::string);
int main()
{
std::string checksum = FileChecksum("C:\\Users\\Dell\\Downloads\\somefile.txt","sha256");
std::cout << checksum << std::endl;
return 0;
}
std::string FileChecksum(std::string file_path, std::string algorithm)
{
EVP_MD_CTX *mdctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
int i;
unsigned int md_len;
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(algorithm.c_str());
if(!md) {
printf("Unknown message digest %s\n",algorithm);
exit(1);
}
mdctx = EVP_MD_CTX_create();
std::ifstream readfile(file_path,std::ifstream::in|std::ifstream::binary);
if(!readfile.is_open())
{
std::cout << "COuldnot open file\n";
return 0;
}
readfile.seekg(0, std::ios::end);
long filelen = readfile.tellg();
std::cout << "LEN IS " << filelen << std::endl;
readfile.seekg(0, std::ios::beg);
if(filelen == -1)
{
std::cout << "Return Null \n";
return 0;
}
EVP_DigestInit_ex(mdctx, md, NULL);
long temp_fil = filelen;
while(!readfile.eof() && readfile.is_open() && temp_fil>0)
{
int bufferS = (temp_fil < MAX_BUFFER_SIZE) ? temp_fil : MAX_BUFFER_SIZE;
char *buffer = new char[bufferS+1];
buffer[bufferS] = 0;
readfile.read(buffer, bufferS);
std::cout << strlen(buffer) << std::endl;
EVP_DigestUpdate(mdctx, buffer, strlen(buffer));
temp_fil -= bufferS;
delete[] buffer;
}
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_destroy(mdctx);
printf("Digest is: ");
//char *checksum_msg = new char[md_len];
//int cx(0);
for(i = 0; i < md_len; i++)
{
//_snprintf(checksum_msg+cx,md_len-cx,"%02x",md_value[i]);
printf("%02x", md_value[i]);
}
//std::string res(checksum_msg);
//delete[] checksum_msg;
printf("\n");
/* Call this once before exit. */
EVP_cleanup();
return "";
}
I tried to write the hash generated by program as string using _snprintf but it didn't worked. How can I generate the correct hash and return the value as string from FileChecksum Function? Platform is Windows.
EDIT: It seems the problem was because of CRLF issue. As Windows in saving file using \r\n, the Checksum calculated was different. How to handle this?
MS-DOS used the CR-LF convention,So basically while saving the file in windows, \r\n comes in effect for carriage return and newline. And while testing on online (given by you), only \n character comes in effect.
Thus either you have to check the checksum of Test Message\r\nHello World\r\n in string which is equivalent to creating and reading file in windows(as given above), which is the case here.
However, the checksum of files,wherever created, will be same.
Note: your code works fine :)
It seems the problem was associated with the value of length I passed in EVP_DigestUpdate. I had passed value from strlen, but replacing it with bufferS did fixed the issue.
The code was modified as:
while(!readfile.eof() && readfile.is_open() && temp_fil>0)
{
int bufferS = (temp_fil < MAX_BUFFER_SIZE) ? temp_fil : MAX_BUFFER_SIZE;
char *buffer = new char[bufferS+1];
buffer[bufferS] = 0;
readfile.read(buffer, bufferS);
EVP_DigestUpdate(mdctx, buffer, bufferS);
temp_fil -= bufferS;
delete[] buffer;
}
and to send the checksum string, I modified the code as:
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_destroy(mdctx);
char str[128] = { 0 };
char *ptr = str;
std::string ret;
for(i = 0; i < md_len; i++)
{
//_snprintf(checksum_msg+cx,md_len-cx,"%02x",md_value[i]);
sprintf(ptr,"%02x", md_value[i]);
ptr += 2;
}
ret = str;
/* Call this once before exit. */
EVP_cleanup();
return ret;
As for the wrong checksum earlier, the problem was associated in how windows keeps the line feed. As suggested by Zangetsu, Windows was making text file as CRLF, but linux and the site I mentioned earlier was using LF. Thus there was difference in the checksum value. For files other than text, eg dll the code now computes correct checksum as string

Read multiple .dat files in C++

I used the code below to read one .dat file and find the execution time, it worked very well. I tried to build a loop to read multiple files as I have more than 20 files with different names (I need to keep their names), but it did not work. How can I develop this code to read all files located in a certain folder no matter how many they are? (based on following code)
#include <Windows.h>
#include <ctime>
#include <stdint.h>
#include <iostream>
using std::cout;
using std::endl;
#include <fstream>
using std::ifstream;
#include <cstring>
/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
* windows and linux. */
uint64_t GetTimeMs64()
{
FILETIME ft;
LARGE_INTEGER li;
/* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
* to a LARGE_INTEGER structure. */
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
uint64_t ret;
ret = li.QuadPart;
ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */
return ret;
}
const int MAX_CHARS_PER_LINE = 512;
const int MAX_TOKENS_PER_LINE = 20;
const char* const DELIMITER = "|";
int main()
{
// create a file-reading object
ifstream fin;
fin.open("promotion.txt"); // open a file
if (!fin.good())
return 1; // exit if file not found
// read each line of the file
while (!fin.eof())
{
// read an entire line into memory
char buf[MAX_CHARS_PER_LINE];
fin.getline(buf, MAX_CHARS_PER_LINE);
// parse the line into blank-delimited tokens
int n = 0; // a for-loop index
// array to store memory addresses of the tokens in buf
const char* token[MAX_TOKENS_PER_LINE] = {}; // initialize to 0
// parse the line
token[0] = strtok(buf, DELIMITER); // first token
if (token[0]) // zero if line is blank
{
for (n = 1; n < MAX_TOKENS_PER_LINE; n++)
{
token[n] = strtok(0, DELIMITER); // subsequent tokens
if (!token[n]) break; // no more tokens
}
}
// process (print) the tokens
for (int i = 0; i < n; i++) // n = #of tokens
cout << "Token[" << i << "] = " << token[i] << endl;
cout << endl;
}
uint64_t z = GetTimeMs64();
cout << z << endl;
system("pause");
}
For listing files in a directory on Windows, refer to this link:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365200(v=vs.85).aspx
Notes about your code:
don't use fin.eof() to test the end of input, see why: eof of istream in C++
to read multiple files, remember fin.clear() before fin.close if you use the same fin to read multiple files.
UPDATE:
The following code prints out the files name in a directory D:\\Test. If you need absolute path for every file or files in subfolders, change GetFiles to do that. This is pretty straightforward according to the link I provided. The code is test on VS2012 Win7 Pro.
#include <windows.h>
#include <Shlwapi.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
#pragma comment(lib, "Shlwapi.lib")
int GetFiles(const string &path, vector<string> &files, const string &wildcard = "\\*")
{
wstring basepath(path.begin(), path.end());
wstring wpath = basepath + wstring(wildcard.begin(), wildcard.end());
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError = 0;
hFind = FindFirstFile(wpath.c_str(), &ffd);
if (INVALID_HANDLE_VALUE == hFind) {
// display error messages
return dwError;
}
TCHAR buf[MAX_PATH];
do {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// directory
} else {
PathCombine(buf, basepath.c_str(), ffd.cFileName);
wstring tmp(buf);
files.push_back(string(tmp.begin(), tmp.end()));
}
} while (FindNextFile(hFind, &ffd));
dwError = GetLastError();
if (ERROR_NO_MORE_FILES != dwError) {
// some errors
}
FindClose(hFind);
return dwError;
}
int main()
{
string path("D:\\Documents\\Visual Studio 2012\\Projects\\SigSpatial2013");
vector<string> files;
GetFiles(path, files);
string line;
ifstream fin;
for (int i = 0; i < files.size(); ++i) {
cout << files[i] << endl;
fin.open(files[i].c_str());
if (!fin.is_open()) {
// error occurs!!
// break or exit according to your needs
}
while (getline(fin, line)) {
// now process every line
}
fin.clear();
fin.close();
}
}
I think it's easier:
1- if you factor out the code that reads a file and process its content into its own function: void process_file( char* filename );
2- add a new function to list a directory's content: char** list_dir( char* dir );
3- combine the 2 functions in your main()
this makes for cleaner and more testable code
I agree with the suggestions to encapsulate this.
On Windows the code looks like this
HANDLE h;
WIN32_FIND_DATA find_data;
h = FindFirstFile( "*.dat", & find_data );
if( h == INVALID_HANDLE_VALUE ) {
// Error
return;
}
do {
char * s = find_data.cFileName;
// Your code here
} while( FindNextFile( h, & find_data ) );
FindClose( h );

Child doesn't terminate correctly in fork

I am writing a c program for a class that is a small shell. The user inputs a command, and the code executes it using the exec() function.
I need to have a fork in the process so all the work is done in the child process. The only problem is that the child won't terminate properly and execute the command. When I run the code without the fork, it executes commands perfectly.
The problem seems to be coming from where I am creating the string to be used in the execv call. It's the line of code where I call strcpy. If I comment that out, things work fine. I also tried changing it to strncat with the same problem. I'm clueless as to what's causing this and welcome any help.
#include <sys/wait.h>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
string *tokenize(string line);
void setCommand(string *ary);
string command;
static int argument_length;
int main() {
string argument;
cout << "Please enter a unix command:\n";
getline(cin, argument);
string *ary = tokenize(argument);
//begin fork process
pid_t pID = fork();
if (pID == 0) { // child
setCommand(ary);
char *full_command[argument_length];
for (int i = 0; i <= argument_length; i++) {
if (i == 0) {
full_command[i] = (char *) command.c_str();
// cout<<"full_command " <<i << " = "<<full_command[i]<<endl;
} else if (i == argument_length) {
full_command[i] = (char *) 0;
} else {
full_command[i] = (char *) ary[i].c_str();
// cout<<"full_command " <<i << " = "<<full_command[i]<<endl;
}
}
char* arg1;
const char *tmpStr=command.c_str();
strcpy(arg1, tmpStr);
execv((const char*) arg1, full_command);
cout<<"I'm the child"<<endl;
} else if (pID < 0) { //error
cout<<"Could not fork"<<endl;
} else { //Parent
int childExitStatus;
pid_t wpID = waitpid(pID, &childExitStatus, WCONTINUED);
cout<<"wPID = "<< wpID<<endl;
if(WIFEXITED(childExitStatus))
cout<<"Completed "<<ary[0]<<endl;
else
cout<<"Could not terminate child properly."<<WEXITSTATUS(childExitStatus)<<endl;
}
// cout<<"Command = "<<command<<endl;
return 0;
}
string *tokenize(string line) //splits lines of text into seperate words
{
int counter = 0;
string tmp = "";
istringstream first_ss(line, istringstream::in);
istringstream second_ss(line, istringstream::in);
while (first_ss >> tmp) {
counter++;
}
argument_length = counter;
string *ary = new string[counter];
int i = 0;
while (second_ss >> tmp) {
ary[i] = tmp;
i++;
}
return ary;
}
void setCommand(string *ary) {
command = "/bin/" + ary[0];
// codeblock paste stops here
You said:
Its the line of code where I call
strcpy.
You haven't allocated any memory to store your string. The first parameter to strcpy is the destination pointer, and you're using an uninitialized value for that pointer. From the strcpy man page:
char *strcpy(char *s1, const char *s2);
The stpcpy() and strcpy() functions copy the string s2 to s1 (including
the terminating `\0' character).
There may be other issues, but this is the first thing I picked up on.

c++ strtok problem

i'm trying to create a map of word==>drow, like polindrom...
the problem is at the final level at "strtok"...
first i split it, then in subsequent call when doing strtok(NULL," "); it works ok.
the problem is when i add the second string "poly_buffer"... seems it works on it....
#include "stdafx.h"
#include <iostream>
#include <cstdio>
#include <string>
#include <map>
#include <string>
using namespace std;
void poly(char *buffer)
{
char temp;
for (int i=0; i<=strlen(buffer); i++)
{
int word_start = i, word_stop = i;
while (buffer[i] != 32 && buffer[i] != '\0') { i++; word_stop++; }
word_stop--;
//swap chars until the middle of word
while (word_stop >= word_start)
{
//swap the chars
temp = buffer[word_stop];
buffer[word_stop] = buffer[word_start];
buffer[word_start] = temp;
word_stop--;
word_start++;
}
word_start = i;
}
}
void main()
{
FILE *fp;
char *buffer;
char *poly_buffer;
long file_size;
map<string,string> map_poly;
fp = fopen("input.txt", "r");
if (fp == NULL) { fputs("File Error",stderr); exit(1); }
//get file size
fseek(fp,1,SEEK_END);
file_size = ftell(fp);
rewind(fp);
//allocate memory
buffer = new char[file_size+1];
poly_buffer = new char[file_size+1];
//get file content into buffer
fread(buffer,1, file_size,fp);
strcpy(poly_buffer,buffer);
buffer[file_size] = '\0';
poly_buffer[file_size] = '\0';
poly(buffer);
buffer = strtok(buffer," ");
poly_buffer = strtok(poly_buffer," ");
while (buffer != NULL)
{
map_poly[buffer] = poly_buffer;
printf("%s ==> %s\n", buffer, poly_buffer);
buffer = strtok(NULL," ");
poly_buffer = strtok(NULL," ");
}
fclose(fp);
while(1);
}
what am i doing wrong ?
the both strtok calls
buffer = strtok(buffer, " ");
poly_buffer = strtok(poly_buffer," ");
are interfering with each other, you need to process them one by one - you cannot do them at the same time because they are sharing static memory in the runtime library. i.e. first do strtok(buffer," ") strtok(NULL, " ") until end, then do strtok( poly_buffer, " ")///
see runtime reference doc for strtok
If you are using C++, why on Earth would you use strtok? Use a stringstream to tokenise and a vector to contain the words:
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
int main() {
istringsream is( "here are some words" );
string word;
vector <string> words;
while( is >> word ) {
words.push_back( word );
}
for ( unsigned int i = 0; i < words.size(); i++ ) {
cout << "word #" << i << " is " << words[i] << endl;
}
}
From the man page for strtok, strtok_r:
"Avoid using these functions."