Trying to write code to concatenate two arrays of pointers to chars (char* example[])

The program should randomly generate a sentence using 4 arrays of prepositions, nouns, adjectives, and verbs. I found a concat algorithm somewhere on the net and modified it to fit my needs but whenever i execute the program it returns 20 blank sentences. It probably has to do with scope, or I am putting my *s in the wrong places. Any help is appreciated

Heres my code:

//******************************************************************************
//*Title: Sentence Lab
//*Author: Micah Vanella	Date: October 24,2007
//*The purpose of this program is to create a series of random sentences using
//* pointer strings.
//******************************************************************************
#include <iostream>
#include <cstdlib>	//For srand and rand
using namespace std;

const int numSent=20;		//Number of sentences to output
const int maxSentSize=128;	//Maximum number of characters in the sentence

//***********************************************************FUNCTION DECLARATIONS

char* makeSentence(char sentence[], char* aArr[], char* nArr[], char* vArr[], char* pArr[], int sizeA, int sizeN, int sizeV, int sizeP);
char* concat(char* first, char* second);
void printSentence(char *sent);

//****************************************************************MAIN FUNCTION

void main(){	
	cout << "Welcome to the Amazing Sentence Maker 4000." << endl;	//Introduction

	cout << "\nPlease enter an integer for the seed value." << endl;//User input of
	int seedval;													// seed value
	cin >> seedval;

	srand(seedval);	//Set the seed using the user specified seed value

	//Articles, nouns, verbs, and prepositions declarations 
	char* article[] = {"the", "a", "one", "some", "every", "any"};
	char* noun[] = {"boy", "girl", "monkey", "LU", "car"};
	char* verb[] = {"drove", "jumped", "ran", "walked", "bit"};
	char* prep[] = {"to", "from", "over", "under", "on"};
	char sent[numSent][maxSentSize];	//To hold each sentence

	//Find the number 
	int sizeA = (sizeof(article)/sizeof(*article));
	int sizeN = (sizeof(noun)/sizeof(*noun));
	int sizeV = (sizeof(verb)/sizeof(*verb));
	int sizeP = (sizeof(prep)/sizeof(*prep));
	
	//Print 20 sentences
	for (int i=0; i<numSent; i++){
		makeSentence(sent[i], article, noun, verb, prep, sizeA, sizeN, sizeV, sizeP);
		printSentence(sent[i]);
	}

	char tempChar;
	cout << "Program ended.\nPlease enter any value and press enter to exit.\n";
	cin >> tempChar;
	return;
}
//************************************************************************************
//*Function: makeSentence
//*Author: Micah Vanella	Date: 10/21/07
//*This function creates the sentence by calling a concatenate function to add
//* each word to the "sentence" array and eventually returning the completed sentence
//*The sentence structure is the following: Article, noun, verb, preposition, article,
//* noun.
//************************************************************************************
char* makeSentence(char sentence[], char* article[], char* noun[], char* verb[], char* prep[], int sizeA, int sizeN, int sizeV, int sizeP){
	*sentence=0;	//Initialize the array of chars
	concat(sentence, article[rand()%sizeA]);
	concat(sentence, noun[rand()%sizeN]);
	concat(sentence, verb[rand()%sizeV]);
	concat(sentence, prep[rand()%sizeP]);
	concat(sentence, article[rand()%sizeA]);
	concat(sentence, noun[rand()%sizeN]);
	return sentence;
}

//**************************************************************************
//*Function: concat
//*Author: Micah Vanella	Date: 10/21/07
//*This function concatenates two strings passed in. It adds the src string
//* to the end of the dst string. It places a space between the two words.
//**************************************************************************
char* concat(char* dst, char* src){
	while (*dst){	//get to the end of the dst string
		++dst;
	}
	*dst++ = ' ';	//add a space between the words then increment
	do{
		*dst++ = *src;	//copy the src string to the end of the dst string
	}
	while (*src++);
	return dst;
}

//**************************************************************************
//*Function: printSentence
//*Author: Micah Vanella	Date: 10/21/07
//*This function takes a sentence string, changes the first character to a
//* capital, then adds a period at the end and sends it to the display.
//**************************************************************************
void printSentence(char *sent){
	toupper(*sent);
	while(*++sent);
	*sent++ = '.';
	*sent = 0;
	cout << sent << endl;
	return;
}

lines 85 thru 88: use a while loop

while( *dest++ = *src++ )
   ;

function printSentence at line 98: you have to save pointer sent before executing lines 100 thru 102, then use the saved pointer in line 103 because as written that function is destroying the value of the pointer.

I fixed the while loop but im still getting the same result as before, just 20 blank sentences.

lines 85 thru 88: use a while loop

while( *dest++ = *src++ )
   ;

function printSentence at line 98: you have to save pointer sent before executing lines 100 thru 102, then use the saved pointer in line 103 because as written that function is destroying the value of the pointer.

do you mean something like this:

void printSentence(char *sent){
	*sent = toupper(*sent);
	while(*++sent);
	*sent++ = '.';
	*sent = 0;
	cout << sent << endl;
	return;
}

?

What's dst pointing to when you return it from concat?

Isn't it modified by address therefore its modified permanently? I was having it just point to itself. I wrote the function to return a value but i figured since it modifies the string anyway I don't need it to return a value. I just left the return in there in case I want to reuse the code later.

function printSentence at line 98: you have to save pointer sent before executing lines 100 thru 102, then use the saved pointer in line 103 because as written that function is destroying the value of the pointer.

do you mean something like this:

void printSentence(char *sent){
	*sent = toupper(*sent);
	while(*++sent);
	*sent++ = '.';
	*sent = 0;
	cout << sent << endl;
	return;
}

?

Isn't it modified by address therefore its modified permanently? I was having it just point to itself. I wrote the function to return a value but i figured since it modifies the string anyway I don't need it to return a value. I just left the return in there in case I want to reuse the code later.

No. All you did is change the first character to upper case. At the end of the function sent point to the end of string where you loaded a 0. Outputting it now simply outputs a null string.

You need to copy the pointer in sent to another variable and use that variable to do your changing. Leave sent alone so it still points to the beginning of the string for outputting.

And it's perfectly acceptable to use a return at the end of a function. It actially helps readability.

Sorry if this is getting annoying to anyone,
I tried the following:

void printSentence(char *sentPtr){
	char *sent = sentPtr;
	toupper(*sent);
	while(*++sent);
	*sent++ = '.';
	*sent = 0;
	cout << sentPtr << endl;
	return;
}

but it just outputs a bunch of crazy characters then errors out. Pointers cause me mental anguish.

It doesn't work because line 4 doesn't do anything. This function will convert the entire sentence to all upper-case. Hope that's what you want to do.

void printSentence(char *sentPtr){
    char *sent = sentPtr;
    while(*sent)
    {
        if(islower(*sent))
	        *sent = toupper(*sent);
        sent++;
    }
    *sent++ = '.';
    *sent = 0;
    cout << sentPtr << endl;
}

[edit] I compiled and ran your original program with the changes I made above and it compiled and ran without error. I did not see the problem you reported.[/edit]

It doesn't work because line 4 doesn't do anything. This function will convert the entire sentence to all upper-case. Hope that's what you want to do.

Or simplify with

void printSentence(char *sentPtr){
    char *sent = sentPtr;
    while(*sent)
    {
       *sent = toupper(*sent++);
    }
    *sent++ = '.';
    *sent = 0;
    cout << sentPtr << endl;
}

toupper() by definition only sets lower case letters to uppercase and will leave all other characters alone.

This function will convert the entire sentence to all upper-case. Hope that's what you want to do.

I just wanted to change the first character in the sentence to uppercase, what would I change to do that?

>I just wanted to change the first character in the sentence to
>uppercase, what would I change to do that?
Don't call toupper on every character, just on the first one:

void printSentence(char *sentPtr){
    char *sent = sentPtr;

    *sent = toupper((unsigned char)*sent);

    while(*sent)
    {
       ++sent;
    }

    *sent++ = '.';
    *sent = 0;
    cout << sentPtr << endl;
}

Don't call toupper on every character, just on the first one:

*sent = toupper((unsigned char)*sent);

I'm slightly confused as to why the unsigned char makes a difference?


On a side note: I spoke to my professor last week and apparently we are able to use strcat, so I started using that and it fixed the program and its been submitted, however i'd still like to know how to concatenate using my own function just for personal use and education.

>I'm slightly confused as to why the unsigned char makes a difference?
toupper takes an integer parameter, but that integer is required to be either EOF or in the range of unsigned char. Because sent holds values that you can't be sure fit in that range, a cast forces the range to avoid undefined behavior.

>however i'd still like to know how to concatenate using
>my own function just for personal use and education.
Here's how one might implement strcat:

char *strcat ( char * dst, const char * src )
{
  char *save = dst;

  while ( *dst != '\0' )
    ++dst;

  while ( ( *dst++ = *src++ ) != '\0' )
    ;

  return save;
}
This article has been dead for over six months. Start a new discussion instead.