Sign in to follow this  

Pointer Problem

This topic is 3743 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been trying to create my own string function but I seem to be getting an error, any help would be greatly appreciated thanks. Class Definition:
char* trimSemiColon(char* string[]);

Function:
char* CString::trimSemiColon(char* string[])
{
	for(int i=0;i<64;i++)
	{
		if(string[i]==";")
		{string[i]="";}
	}
	return string[64];
}

This is my error:
Quote:
error C2664: 'trimSemiColon' : cannot convert parameter 1 from 'char (*)[64]' to 'char *[]' Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

Share this post


Link to post
Share on other sites
The error tells you; the type you are calling trimSemiColon with (char (*)[64]) is not implicitly convertable to the parameter type (char *[]) and an explicit cast of the listed types is required.

Why are you dealing with raw char pointers for strings when you have std::string? And for that matter, if you're rolling your own CString class for education purposes (fine, so long as you never use it in production code), why are you still passing and returning char* instead of instances of your CString class?

Finally, your code is dangerous. You're assuming the input array of char* is 64 elements long, and your returning an invalid element (the legal range of indices for a 64-element array is 0 through 63, inclusive).

You also cannot compare char* strings with operator==, that just compares the addresses of the pointers involved, not the content. It will work as you expect sometimes, and fail unexpectedly other times. When dealing with char* strings you must use C standard libary functions (like strncmp) or manually iterate the string and compare each character yourself. It also seems like you're treating an array of char* as a single logical string -- your tests are all against single character strings -- instead of the more idiomatic method of treating a char* as a pointer to an array of characters (';' versus ";") representing the string. Your interpretation is woefully poor in terms of cache coherency (this kind of subtle mistake is a good example of why, while you may write them for educational use, you should never use your hand-rolled string classes in real code, et cetera).

Share this post


Link to post
Share on other sites
You are confusing pointers, string literals and characters.

In C, text is represented by character arrays. Frequently these character arrays are stored on the heap, and accessed via a pointer. String literals are often held in read only memory and are also accessed by a pointer. Arrays of other objects are also often accessed through a pointer.

In C++, text is represented by std::string objects. Arrays are best represented as std::vector objects. We can use predefined algorithms from the C++ Standard Library to manipulate containers, including std::vector.

In C++, I would write:

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>

// if you want to totally remove semicolons
void trimSemiColon( std::vector<std::string> &stringArray)
{
std::vector<std::string>::iterator it = std::remove(stringArray.begin(),stringArray.end(),";");
stringArray.erase(it,stringArray.end());
}

// if you want to replace them with empty string.
void trimSemiColon( std::vector<std::string> &stringArray)
{
std::replace(stringArray.begin(),stringArray.end(),std::string(";"),std::string());
}

int main()
{
std::vector<std::string> strings;
strings.push_back("hello");
strings.push_back(";");
strings.push_back("goodbye");
trimSemiColon(strings);
// strings now contains:
// "hello", "goodbye" with option 1 above
// "hello", "", "goodbye" with option 2.
}




In C, the code would be more complicated due to manual memory management issues. For example, the ownership of the pointers passed to the function must be understood and respected. Im going to assume all the strings are stored on the heap, and will be freed with the array. We also need to know the length of the array. We'll pass it as a parameter, not use hard coded magic numbers.


// dont return a value unless it has meaning
// I dont understand the "meaning" behind returning
// one past the last element in the array

// also, apologies if this code is incorrect

// note: caller must guarantee all strings stored on the heap
// and that the array elements will be freed at some point in the future.
void trimSemiColon( char **stringArray, int numStrings ) {
for( int i = 0 ; i < numStrings; ++i ) {
if(strcmp(stringArray,";") == 0) {
free(stringArray[i]);
// we only need a NUL char
// sizeof(char) is guarenteed to be 1.
stringArray[i] = malloc(1);
if( stringArray[i] == NULL ) { /* handle error */ }
stringArray[i][0] = '\0';
// alternatively
// strcpy(stringArray[i],"");
}
}
}



...nasty.

However, since we can use the C++ version we will, its much easier. [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by CM_Marcus
I've been trying to create my own string function but I seem to be getting an error, any help would be greatly appreciated thanks.


Stop. What do you want it to do? In English, please. Forget that you ever wrote any C or C++ ever in your life. What kind of thing will you provide as input (use an English description, not code)? What kind of thing will you provide as output (use an English description, not code)? How should the input relate to the output?

Share this post


Link to post
Share on other sites
Uh, I might be a newb myself (which I most likely am), but this code doesn't make sense.

First, you take a pointer to a string of undefined length.
Then you try to return a 64 length array that magically appeared somewhere.

Not to mention that this function is a member of a class, and yet the input and output information seem to be trying to operate on external data.

A string class should have:


class myStringClass
{
...
private:
char *myString;
..
};


void myStringClass::trimSemicolon()
{
for (int i=0; i < strlen(myString); i++)
{
if( string[i]==';' ) { string[i]=='';}
}
}


This way your code actually makes sense, as it works on internal members of the class, and the function does what it's supposed to do, removes the semicolons within the parent string.
Since this is a member of the class, you do not need to input or output anything, as you have direct access to the data you try to modify.

I hope this makes sense ;-)

Share this post


Link to post
Share on other sites
Thanks for all your posts.

I was aware of the limitations of the function, and it was created to do a specific function in a specific program, ie removing the semicolons from lines read from a file. Where 64 characters were read at a time (hence the i<64)

I have had problems trying to use the std string functions, hence I tried to write my own, which didn't work out too well XD.

Does anyone know a good online tutorial or something to help me with the std string functions?

Share this post


Link to post
Share on other sites
Quote:
Original post by DeafManNoEars
Quote:
Original post by NestorPL

Then you try to return a 64 length array that magically appeared somewhere.


No he's not.... He is returning the 65th element in a (supposedly) 64 element char array.


Avast, that be a mighty fine point thar. I must be gettin' old me thinks.. Touche!

Thank thee lad!

CM_Marcus, thar was a thread driftin' here a couple days ago, with some young sailor dilimiting his strings usin' strtok, thar was some good advice in there, try lookin' fer it.

Wind at your back!

EDit: That be the link yer lookin' fer http://www.gamedev.net/community/forums/topic.asp?topic_id=464160

[Edited by - NestorPL on September 19, 2007 2:08:11 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by CM_Marcus
Thanks for all your posts.

I was aware of the limitations of the function, and it was created to do a specific function in a specific program, ie removing the semicolons from lines read from a file. Where 64 characters were read at a time (hence the i<64)


So, your input should be *one* string, not an array of them. And since you're going to change its contents, you don't need to return anything; but if you did, it would probably just be the original string. Unless you wanted to make a copy - but then you'd have to allocate memory for the copy, and worry about who was going to clean it up.

But before you can even attempt these things, you have to understand what a char* is.

First off, it is not the string. It's a pointer to a character. Characters are the elements of strings. Maybe you've seen source code with things like ';' in it, as opposed to ";". That's because the former declares a character literal, and the latter declares what is very unfortunately called a string literal.

';' is a number, stored in one byte (in C++; in C, it's in an int-sized chunk of memory - unless I got that the wrong way around again) which corresponds to a semicolon when looked up in the ASCII table.

";" is, very roughly speaking, a number which corresponds to a location in memory. The byte at that location holds a number that corresponds to a semicolon when looked up in the ASCII table (i.e., we can find ';' there). The next byte in memory after that location holds a zero value, which indicates (by convention) the end of the string.

This is actually a very bad way of representing strings, even disregarding the obvious problems with memory management. It makes lots of string operations much slower than they need to be. Plus, it means you can't use the symbol that happens to correspond to ASCII 0 in the middle of your text (because the rest of the text after that would be ignored). But we're stuck with it, because C++ evolved from C, which evolved from earlier languages, way back in the 70s. They did it that way to save memory: no matter how long your string was, the "length information" - where to stop - would always fit in one byte. With the obvious scheme - counting the length, and storing that separately in some kind of structure - it would cost a few bytes more, at least if you wanted to support strings more than 255 bytes long. Yeah, memory could be appropriately measured in bytes back then, so that kind of thing was important.

Anyway, what you *seem* to be trying to do, notwithstanding all the types being horribly wrong, is to scan through the bytes of the string, find those which correspond to semicolons, and then replace them with nothing. Well, unfortunately, that doesn't work: you can't cause a byte of memory to cease to exist, and the surroundings to magically join up around the void. You would need to instead shift the following chunk of memory into place. *Would*, except that all these things already exist :)

Quote:

I have had problems trying to use the std string functions, hence I tried to write my own, which didn't work out too well XD.


Writing your own function to operate upon a std::string when you don't need to makes about as much sense as trying to fix your car's engine because the mechanic is closed for the day.

Trying to do it with char* input makes about as much sense as trying to *replace* your car's engine for the same reason. You can still treat a std::string *just like* the old C strings, when you really need to. A little care is involved when you call someone *else's* ancient function that refuses to accept a std::string, but you can do your *own* manipulation on it just like we all used to with raw char*s. Hint: std::string provides an operator[].

Quote:
Does anyone know a good online tutorial or something to help me with the std string functions?


This forum.

Share this post


Link to post
Share on other sites

This topic is 3743 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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

Sign in to follow this