C/C++ How to Track Array Positions of Words in a C++ Sentence?

  • Thread starter Thread starter Math Is Hard
  • Start date Start date
  • Tags Tags
    Array Tracking
AI Thread Summary
The discussion revolves around traversing an array containing a user-inputted sentence to identify the positions of the first and last letters of each word. Participants explore methods to track the positions of letters while handling spaces and the null terminator at the end of the string. Key points include the need to maintain a state indicating whether the current character is part of a word, and the importance of distinguishing between letters and non-letters to determine when to record positions. Various code snippets are shared, demonstrating different approaches, including the use of flags and for-loops to manage the traversal. The conversation also touches on passing arrays to functions in C++, clarifying that arrays are passed by reference, allowing for direct manipulation without needing to return them. Overall, the thread emphasizes understanding character states and effective loop management to achieve the desired output of letter positions in the sentence.
Math Is Hard
Staff Emeritus
Science Advisor
Gold Member
Messages
4,650
Reaction score
39
I believe I am stuck. :frown: I need to traverse an array which will contain a sentence the user enters and identify the array positions of the first and last letters of each word in the sentence. I can do the first word, but I am not sure how to move it along after that. I am thinking I need to always store my last position of a previous word and use that when finding the first position of a new word but not sure how to do this. And I'm not sure how to move past the white spaces, but also stop at the end of the array. Thanks for any help.
For an example - Desired output for sentence "my dog barks." would be:
first letter array position: 0
last letter array position: 1
first letter array position: 3
last letter array position: 5
first letter array position: 7
last letter array position: 11

Code:
#include <iostream>
using namespace std;

int main()
{
	char sentence[80];

	cout <<"Enter a sentence (no caps): \n";
	cin.getline(sentence,80);

	int i = 0;
	while (sentence[i] != '\0')
	{		
		if (sentence[i] <'a' || sentence[i] >'z')
		{			
			int last = i-1;
			int first = 0;
			cout << "first letter array position: " <<first <<endl;
			cout << "last letter array position: " <<last <<endl;			
		}
	i++;
			
	}
 	return 0;	
}
 
Technology news on Phys.org
At any given time, the program needs to know whether or not it is currently processing a word. It also needs to know what to do when that state changes.

How should the program tell that the state has changed? Well, if the current character is a letter, the state has changed if the previous character was not, and vice versa.

So, each time through the loop there are basically two questions:
  1. Is the current character a letter, a non-letter, or null?
  2. Was the previous character a letter?
So there are six possible cases to take care of.

As an example, suppose the current character is a letter, and the previous one was not. That means we're at the beginning of a word. Thus (depending on how you want the program to work), you should either print the "first letter" message or store the position for future reference.

Note that the different phrasing of the two questions is significant, and is a hint for dealing with the loop bounds (i.e. think about how the processing needs to deal with the first character of the array – which itself could be a letter or not).

Also, note that when processing the end of the string it makes a difference whether the character prior to the null was a letter or not. Given the suggested input "my dog barks", the included code will only indicate two words.

Minor quibble: for the included code as it stands, it would be more idiomatic to use a for-loop:
for(int i=0; sentence != '\0'; ++i) { ...
 
Last edited:
hi plover, I made some progress since my last post. I still have to work out dealing with that null character at the end. Do you think this approach is any better?

Code:
#include <iostream>
using namespace std;

int main()
{

	char sentence[80];

	cout <<"Enter a sentence (no caps): \n";
	cin.getline(sentence,80);

	int first, last;
	int i = 0;
	bool flag = 0;
	while (sentence[i] != '\0')
	{
		

	if ((sentence[i] >='a' && sentence[i] <='z') && (flag == 0))//is letter and we're looking for a letter
	{
		first = i;
		flag = 1;
		i++;
	}

	else if ((sentence[i] >='a' && sentence[i] <='z') && (flag == 1))//is letter but we're looking for 'non-letter'
	{
		i++;
	}

	else if ((sentence[i] <'a' || sentence[i] >'z') && (flag == 1)) //is non-letter and we're looking for non-letter
	{	
		last = i-1;
		cout << "first letter array position: " <<first <<endl;
		cout << "last letter array position: " <<last <<endl;	
		flag = 0;
		i++;
	}
	
	else //it's non-letter but we're looking for letter
	{
		i++;
	}
			
	}

 	return 0;
	
}
 
plover said:
Minor quibble: for the included code as it stands, it would be more idiomatic to use a for-loop:
for(int i=0; sentence != '\0'; ++i) { ...

I'm just trying to follow my teacher's examples here. He actually had some reason for not using a for loop in some of the related examples - I remember because somebody asked him about it - it was something about the "complexity of the conditional" I think he said. I can't remember exactly. I think he just didn't want to confuse us since we're beginners.
 
Why don't you try this:

Code:
#include <iostream>
using namespace std ;

int main( int argc, char **argv ) {

	char sentence[80] ;
	bool first = true ;

	cout << "Enter a sentence (no caps):" << endl;
	cin.getline( sentence,80 ) ;
	
	for( int i=0; sentence[i] != '\0'; i++ ){
		if( first && sentence[i] >= 'a' && sentence[i] <= 'z' ) {
			cout << "First letter array position: " << i << endl ;
			first = false ;
		} else if ( !first && (sentence[i] < 'a' || sentence[i] > 'z') ){
			cout << "Last letter array position: " << i-1 << endl ;
			first = true ;
		}
	}
				
	return 0 ;
}
 
hey dd - thanks! but what are those arguments in main()?
 
Those are for the command line. You don't have to have them if you don't want. It will be assumed void if you don't put any main arguments.
 
ah, ok. Thanks. I have this vague memory of them from a C class I took now.
 
I just thought of a question I've been wondering about. Can you pass an array into a function, do stuff to it, and pass it back out again? thx.
 
  • #10
Arrays, by default, are passed by reference to functions. Therefore, if you have a function with parameters like this

int myfunction( int *array ) { /*code*/ }

Then you can do something like this:

int array[3] ;

myfunction(array) ;

The base address is passed onto myfunction and you can manipulate the array to your hearts content. There is no need to return the array back because your addressing the memory directly.
 
  • #11
thanks. I wasn't sure what I could do. Our TA mentioned manipulating the array inside a function, but the teacher hasn't lectured on this yet, so I wasn't sure if it was the same method as in C programming or something different.
 
  • #12
The problem is that the null character can't be treated specially until after it's been processed. This can be done with a do-while-loop or by using a break statement.

This was my version:
Code:
#include <iostream>
using namespace std ;

int main() {

    char sentence[80] ;

    cout << "Enter a sentence (no caps):" << endl;
    cin.getline( sentence,80 ) ;

    for(int first=-1, pos=0; ; ++pos) {
        bool letter = (sentence[pos] >= 'a' && sentence[pos] <= 'z');
        if(first < 0) {
            if(letter) first = pos;
        } else {
            if(!letter) {
                cout << "first letter array position: " << first << endl;
                cout << "last letter array position: " << (pos-1) << endl;
                first = -1;
            }
        }
        if(sentence[pos] == '\0') break;
    }
    return 0 ;
}
Math Is Hard said:
I just thought of a question I've been wondering about. Can you pass an array into a function, do stuff to it, and pass it back out again? thx.
Yes, passing an array to a function works by passing the address of the first array element. Thus, operations on the elements of the array will be persistent when the function returns (no need to return the pointer). Also, remember from C that the contents of the address referred to by a pointer can be accessed like an array.

So if a function is declared like this:
void messWithString(char* aString);
It can be used like this:
char someText[] = "yadda yadda yadda";
messWithString(someText);
 
  • #13
thanks, plover. I always get really confused on anything that is pass-by-reference or anything involving pointers. I don't think I ever learned it very well. I better go make some simple examples of "messwithstring" functions and see what I can do.
Your program is really great - it catches all the first and last letters! - but it will take me a while to understand how it works.
A question I have about:
for(int first=-1, pos=0; ; ++pos)
why is there an empty space between the ; ; where you would normally put a condition?
 
  • #14
Math Is Hard said:
Your program is really great - it catches all the first and last letters! - but it will take me a while to understand how it works.
A question I have about:
for(int first=-1, pos=0; ; ++pos)
why is there an empty space between the ; ; where you would normally put a condition?
All three clauses of the for-loop mechanism are optional, but the two semi-colons are required. There's no good way to put the condition at the top of the for loop that will allow the loop to be executed for the case of the current character being the terminal null, so I just left it out. The loop could also be:
int first=-1, pos=0;
do { ... } while(sentence[pos++] == '\0');
but this does not restrict the scope of first and pos to the loop.

Also, while it's arranged a little differently, the logic of the if-statements inside the loop in my version is actually nearly identical to that of dduardo's version.
 
  • #15
I knew that in this case that the string would be limited to 80 chars, so I ended up just doing this:
for( int i=0; i<80; i++ )

and then breaking if '\0' is encountered.
I guess that's OK..?? I had tried a do while loop first but didn't have much luck.

Oh, and I worked out some functions that manipulate the string - worked great!

tahkns for yuor hlep :smile:
 
Back
Top