Jump to content

Pointer to pointer (C)

ShatteredPsycho

Hello everyone,

So I have this exercise (on pointers introduction), last one of the exercise sheet I am doing that states:

Quote

Implement a function void find_all_words(char* str, char* word, char** addrs) that, using
the function developed in the previous exercise, find all the occurrences of a word in a string.
The function should populate the array addrs with the all the addresses of the word found in
str. Ensure that the array addrs has enough space to accommodate all the possible addresses.

 

Now I figured I would just run my code until I got to the end of the string (the previous exercise was to just find a single word on a string) but I am not sure how to use the char** addrs, i looked up the uses for the pointer to the pointer but still can't make out how to use it in this case.

My code is this:

char* find_word(char* str, char* word, char* initial_addr) {
	int flag=0;
	char *temp;
	char* orig = word;
 	while(1){
    if(*word == *initial_addr){
			if(flag !=1){
				temp = initial_addr;
			}
      		flag = 1;
			initial_addr++;
			word++;
      }else{
     		 if(*initial_addr == ' ' && flag == 1){
					return temp;
			}else{
					temp = NULL;
				}
      		word = orig;
      		flag =0;
      		initial_addr++;
			}
      if(*initial_addr == '\0'){
			return NULL;
		}
	}
}

Where in the main function I subtract the size of the temp string to the original string and get the address where it starts.

Can anybody tell me how I go about this?

Link to comment
Share on other sites

Link to post
Share on other sites

Since char** addrs is an array of some sort that holds all of the instances of word that you find in string str, you pass the function an array of char*, which you use a double pointer to point to it. i.e.,

char* found_words[10] = {0}; //I'm just picking a size here
char** found_words_start = (char**)(found_words); // This will point to the start of the array found_words

So you'd pass in found_words_start. In the function proper you can use addrs as an array

 

My only hiccup is allocating an array. I provided a naive solution. If this were a more serious solution, you'd have to create an array of appropriate size at runtime using malloc (and making sure to delete it using free, lest you want memory leaks) before passing it into the function. Which means you also have to figure out how many instances of the word there are in the first place.

Link to comment
Share on other sites

Link to post
Share on other sites

2 minutes ago, M.Yurizaki said:

Since char** addrs is an array of some sort that holds all of the instances of word that you find in string str, you pass the function an array of char*, which you use a double pointer to point to it. i.e.,


char* found_words[10] = {0}; //I'm just picking a size here
char** found_words_start = (char**)(found_words); // This will point to the start of the array found_words

So you'd pass in found_words_start. In the function proper you can use addrs as an array

 

My only hiccup is allocating an array. I provided a naive solution. If this were a more serious solution, you'd have to create an array of appropriate size at runtime using malloc (and making sure to delete it using free, lest you want memory leaks) before passing it into the function. Which means you also have to figure out how many instances of the word there are in the first place.

I did what you said, and I understand what you said on the last part.

 

From my code I got this:

Word found in the address: 0x1

 

Which I think is wrong, or at least unusual and there should have been 2 found, not one.

 

So far I have:

int main(){
	char str[]={"to those where to are"};
	char word[]={"to"};

	char* a_addrs[1];
	char **addrs = (char**)(a_addrs);
	int i=0;
	find_all_words(str,word,addrs);
	for(i=0;i<1;i++){
		printf("A palavra %s foi encontrada no endereço: %p\n",word,addrs[i]);
	}
	return 0;
}

and

#include <stdio.h>

void find_all_words(char* str, char* word, char** addrs) {
	int flag=0,count=0,dcount=0;
	char *temp;
	char* orig = word;
	while(*str == '\0'){
		if(*word == *str){
			if(flag !=1){
				temp = str;
				count=0;
			}
			flag = 1;
			str++;
			word++;
		}else{
				if(*str == ' ' && flag == 1){
					*addrs = str;
					dcount++;
					addrs++;
					word =orig;

				}else{
					temp = NULL;
				}
				word = orig;
				flag =0;
				str++;
			}
	}
}

 

Link to comment
Share on other sites

Link to post
Share on other sites

1 minute ago, ShatteredPsycho said:

I did what you said, and I understand what you said on the last part.

 

From my code I got this:

Word found in the address: 0x1

 

Which I think is wrong, or at least unusual and there should have been 2 found, not one.

 

So far I have:


int main(){
	char str[]={"to those where to are"};
	char word[]={"to"};

	char* a_addrs[1];
	char **addrs = (char**)(a_addrs);
	int i=0;
	find_all_words(str,word,addrs);
	for(i=0;i<1;i++){
		printf("A palavra %s foi encontrada no endereço: %p\n",word,addrs[i]);
	}
	return 0;
}

and


#include <stdio.h>

void find_all_words(char* str, char* word, char** addrs) {
	int flag=0,count=0,dcount=0;
	char *temp;
	char* orig = word;
	while(*str == '\0'){
		if(*word == *str){
			if(flag !=1){
				temp = str;
				count=0;
			}
			flag = 1;
			str++;
			word++;
		}else{
				if(*str == ' ' && flag == 1){
					*addrs = str;
					dcount++;
					addrs++;
					word =orig;

				}else{
					temp = NULL;
				}
				word = orig;
				flag =0;
				str++;
			}
	}
}

 

In your main() function, you made an array of size one, so it's going to point out there's one instance. Also since addrs is pointing to an array of size one, the addrs++ in find_all_words will put the pointer out of the array bounds. Since I'm going to assume you can't change what you can pass in find_all_words, you're going to have to guarantee the size of the array matches how many instances of the words there are before you call the function.

Link to comment
Share on other sites

Link to post
Share on other sites

1 minute ago, M.Yurizaki said:

In your main() function, you made an array of size one, so it's going to point out there's one instance. Also since addrs is pointing to an array of size one, the addrs++ in find_all_words will put the pointer out of the array bounds. Since I'm going to assume you can't change what you can pass in find_all_words, you're going to have to guarantee the size of the array matches how many instances of the words there are before you call the function.

For this example I know I am getting 2 values for the array, that's why I made the size 1(0 and 1). Is that wrong? It's for the single use case. 

 

Link to comment
Share on other sites

Link to post
Share on other sites

Just now, ShatteredPsycho said:

For this example I know I am getting 2 values for the array, that's why I made the size 1(0 and 1). Is that wrong? It's for the single use case. 

 

When you declare an array, you are saying how many elements there are. So saying array[1] means you're making an array of one element.

 

You address arrays starting from 0 because it's an offset. The [] operator is shorthanding *(array + offset).

Link to comment
Share on other sites

Link to post
Share on other sites

3 minutes ago, M.Yurizaki said:

When you declare an array, you are saying how many elements there are. So saying array[1] means you're making an array of one element.

 

You address arrays starting from 0 because it's an offset. The [] operator is shorthanding *(array + offset).

I tried with size 2 and 4 and got 0xb75f4f03

Still not getting the two addresses, what should I use? Do you see anything wrong in the find:_all_words method?

Just now, M.Yurizaki said:

Also I don't see any reason to believe you can't make helper functions to support find_all_words from your prompt. :)

not sure what you mean

Link to comment
Share on other sites

Link to post
Share on other sites

9 minutes ago, ShatteredPsycho said:

I tried with size 2 and 4 and got 0xb75f4f03

Still not getting the two addresses, what should I use? Do you see anything wrong in the find:_all_words method?

First your for loop needs to change how many iterations it does.

 

Second you're spitting out the address of where the pointer is pointing at. You need to change the format specifier to %s and deference addrs since addrs[i ] will spit out a pointer.

Quote

not sure what you mean

What I'm saying you don't have to do everything in find_all_words. If it helps to make functions to perform certain steps, then you should do it.

Link to comment
Share on other sites

Link to post
Share on other sites

3 minutes ago, M.Yurizaki said:

First your for loop needs to change how many iterations it does.

 

Second you're spitting out the address of where the pointer is pointing at. You need to change the format specifier to %s and deference addrs since addrs will spit out a pointer.

What I'm saying you don't have to do everything in find_all_words. If it helps to make functions to perform certain steps, then you should do it.

The modular part, I follow.

 

I get this with %s ���P

 

Link to comment
Share on other sites

Link to post
Share on other sites

Just now, M.Yurizaki said:

Are you dereferencing the pointer you get with addrs[ i]?

Yes
printf("A palavra %s foi encontrada no endereço: %p\n",word,addrs);

Link to comment
Share on other sites

Link to post
Share on other sites

Just now, ShatteredPsycho said:

Yes
printf("A palavra %s foi encontrada no endereço: %p\n",word,addrs);

If you just do addrs, you're asking for the memory address of the start of the array.

 

Recall that addrs is an array of char pointers. So when you iterate through addrs, you're getting pointers.

Link to comment
Share on other sites

Link to post
Share on other sites

3 minutes ago, M.Yurizaki said:

If you just do addrs, you're asking for the memory address of the start of the array.

 

Recall that addrs is an array of char pointers. So when you iterate through addrs, you're getting pointers.

Ok, I think I got it

Thanks for the help ;) 

Link to comment
Share on other sites

Link to post
Share on other sites

13 hours ago, ShatteredPsycho said:

So far I have:


	char* a_addrs[1];
	char **addrs = (char**)(a_addrs);
	find_all_words(str,word,addrs);

 

I'd advice against the cast. It is unneeded as arrays decay into pointers in C anyway, but it does circumvent compiler error checking.

You can simply do this:

	char* a_addrs[1];
	char **addrs = a_addrs;
	find_all_words(str,word,addrs);

And from that follows this will work fine too:

	char* a_addrs[1];
	find_all_words(str,word,a_addrs);

Casting, as you're doing in your code, is basically telling the compiler "Shut up and make this conversion, even if it were a conversion that is not allowed, I know what i'm doing".

That means this would work without any compiler error:

	int* a_addrs[1];		  //Array of int pointers!
	char **addrs = (char**)(a_addrs); //Force conversion to char pointer to pointer by casting...
	find_all_words(str,word,addrs);	  //..Probably not going to do what you want :(

Whereas the version without the cast will emit a error along the lines of "incompatible pointer types" or "Invalid conversion from "int** to char**".

 

Secondly, when reading the exercise, I believe the point is to make function "find_all_words" in such a way that it in turn repeatedly calls the function "find_word" to find the actual words, not re-implement it from the ground up. That's probably the catch why that function took the superfluous 'initial_addr' pointer we were talking about in a earlier post. It makes this task easier.

 

You should be splitting things up into functions anyway, that way things become much more readable, manageable and less error prone. The function 'find_word' could delegate the comparison of the current search location in the string with the word to search to another function, making things much simpler. Most of this example is comment, the actual code is now small and simple:

#include <stdbool.h>  //Include stdbool.h for the bool type.

bool
contains_word_at_current_loc(const char* string, const char* word)
{	
	while (1)	//Loop forever.
	{
		if (*word == 0)		//If we reached the terminating 0 on the word to look for...
		{
			return true;	//...then we have a match. (or word is a empty string)
		}
		if (*string == 0)	//If we reached the terminating 0 on the string to check...
		{
			return false;	//...then the string ended before we found the whole word, no match.
		}			//Note that we now tested both strings for their 0-terminator in the...
					//...beginning of the loop. This ensures we never go out of bounds on...
					//...either string.
      
		if (*word != *string)	//If the current character does not match...
		{
			return false;	//...then obviously no match.
		}
		++word;
		++string;		//Increase pointers for next character.
	}
}   

const char* 
find_word(const char* str, const char* word, const char* initial_addr)
{
	while (*initial_addr != 0)	//Loop as long as we did not reach the terminating 0 on initial_addr string.
	{
		if (contains_word_at_current_loc(initial_addr, word)) //Test if word is in string at current location.
		{
			return initial_addr;	//If yes, return pointer to current location.
		}
		++initial_addr;	//Move to next character. 
	}
	return NULL;	//Return NULL if we reached initial_addr's 0 terminator without finding the word.
}

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×