Ah yes, a copy and paste error on my part. Forgot to give the "untested" disclaimer on that code.
One more thing: Although you're noted that you don't need a resizeable array. You can see that you are having to perform two passes over the data instead. Once to count the newlines, and then once to get the pointer to the strings. If you use a vector, then you can do it all in one pass. For each newline you find, you can just push_back the string immediately.
Efficiency wise there's probably not much difference, but if you can do it in less code then there's less room for bugs.
Are you writing an interpreter or someting like that?
My homepage
Advice: Take only as directed - If symptoms persist, please see your debugger
Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"
Not sure if that's what you really meant, but I wasn't *counting* new-line characters. I was only using them as a separation character between individual strings contained in a single string. So I simply was looping through the string, and adding characters to anotherStr as long as the current character was not a newline character. This is done in a while loop inside a for loop. Once the while loop completes each iteration of the for loop, I was simply pointing at the string being pointed at by anotherStr with the current element pointer of the array of pointers. As for vector:ush_back(), I'm not sure exactly what you mean by that either. What that function does is appends to the end of the string, and performs the same function as the += operator of the string class, and I wasn't wanting to add the new-line characters to the anotherStr, before pointing at the resulting anotherStr with the current element of the array of pointers, because the result strings weren't supposed to contain any new-line characters.
Not exactly. I was originally writing a program for web coding in various languages, but then I had need of a function which could get the string names of an enum member, and I went looking for that, without finding anything for that. So I then decided to write my own program which could take a file containing an enum (or multiple enums) and output some kind of interface to file which would make retrieving enum value string names a piece of cake, regardless of what the enum is. That is when I decided I wanted a function which would return a const char* array of which each element is pointed at the relevant string of the enum value name, which resulted in this current thread.Efficiency wise there's probably not much difference, but if you can do it in less code then there's less room for bugs.
Are you writing an interpreter or someting like that?
Anyway, I got the code to work using an array of pointers finally (even though I decided to go with vectors instead):
This works as expected, and outputs:Code:#include <iostream> #include <string> using namespace std; struct stringStruct { stringStruct() : arrayOfPointers(NULL) { initialize(); } void initialize(); string* str; string* anotherStr; const char** arrayOfPointers; }; void stringStruct::initialize() { str = NULL; anotherStr = NULL; } void doStuff(); int main() { doStuff(); cout<< "\nHaha, you got to press Enter."<<endl; cin.get(); return 0; } void doStuff() { stringStruct object; object.str = new string; *object.str = "Yes, a string...\n"; *object.str += "Yes, another string...\n"; *object.str += "Yes, even another string...\n"; int sizeOfStr = object.str->size(); object.anotherStr = new string; int sizeOfArrayOfPointers = 3; object.arrayOfPointers = new const char*[sizeOfArrayOfPointers]; int i2 = 0; for (int i = 0; i < sizeOfStr; i++) { if (object.anotherStr == NULL) { object.anotherStr = new string; } if (object.str->at(i2) == '\n') { //we're at a new-line character i2++; //increment so as to skip the new-line character to the next character, which wont be a new-line character } if (i == sizeOfArrayOfPointers - 1) { //we're at the last element of the array of pointers for (int num = i; num < sizeOfStr; num++) { //continue looping through object.str... if (object.str->at(i2) == '\n') { //we're at a new-line character i2++; //increment so as to skip the new-line character to the next character, which wont be a new-line character } while (object.str->at(i2) != '\n') { *object.anotherStr += object.str->at(i2); i2++; } object.arrayOfPointers[num] = object.anotherStr->data(); object.anotherStr = NULL; for (int i = 0; i < sizeOfArrayOfPointers; i++) { cout<< object.arrayOfPointers[i] <<endl; } delete object.str; delete object.anotherStr; delete [] object.arrayOfPointers; return; } } while (object.str->at(i2) != '\n') { //iterate till the next new-line character *object.anotherStr += object.str->at(i2); //add characters to the "anotherStr" i2++; } object.arrayOfPointers[i] = object.anotherStr->data(); object.anotherStr = NULL; //reset this pointer } }
Yes, a string...
Yes, another string...
Yes, even another string...
Yes you were. How else do you know how large to allocate arrayOfPointers?!Not sure if that's what you really meant, but I wasn't *counting* new-line characters.I love how you are able to use the word "simply" in there. Using that word does not make it true.I was only using them as a separation character between individual strings contained in a single string. So I simply was looping through the string, and adding characters to anotherStr as long as the current character was not a newline character. This is done in a while loop inside a for loop. Once the while loop completes each iteration of the for loop, I was simply pointing at the string being pointed at by anotherStr with the current element pointer of the array of pointers.
What's more, it probably isn't actually doing what you think it's doing. I know this both because your descriptions don't quite make sense and because you've still failed to realise why allocating those strings dynamically does not do anything good for that piece of code. If you understood how it really worked you'd realise this. I've already shown how that unnecessary complication can be avoided in a code example.I mean exactly what anyone else who mentions it means. The mere mention of it to most C++ programmers should immediately put you both into a state of mutual understanding. You don't know about much of the most commonly used stuff in the standard C++ Library and that is most unfortunate for you as your job will be that much harder without it.As for vector::push_back(), I'm not sure exactly what you mean by that either.It makes sense that your description would be as convoluted as your code is. They both come from the same thought process. You need to learn to think about the effect you are trying to achieve at a higher level.What that function does is appends to the end of the string, and performs the same function as the += operator of the string class, and I wasn't wanting to add the new-line characters to the anotherStr, before pointing at the resulting anotherStr with the current element of the array of pointers, because the result strings weren't supposed to contain any new-line characters.
Well, what you've ended up with is far from pretty. It has memory leaks and usage of string::data() that is almost certainly going to mean trouble in your real code. Any attempt to return an array of const char *'s along the lines of what you've been doing is pretty much going to guarantee a memory leak or accessing deleted memory.
Do you realise that you have a for-loop there that will never loop? In other words, it's equivalent to just an if-statement.
Well it's all for your own benefit. Perhaps if you get stuck in and learn more about the language you'll come to look back on this code one day and realise how far you've come. If that happens - mission accomplished.
Last edited by iMalc; 05-22-2010 at 10:01 PM.
My homepage
Advice: Take only as directed - If symptoms persist, please see your debugger
Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"
Only because you got lucky. Consider:
Can you see a problem with this code? If not, I would highly recommend that you stick with the pre-made stl objects (std::string, std::vector, etc) until you've got a really firm grasp on how pointers work, their implications, etc.Code:object.arrayOfPointers[i] = object.anotherStr->data(); object.anotherStr = NULL; //reset this pointer
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
It seems to me that this would be a good time for you to learn about the STL and the power, and responsibility, it brings. The STL is a truly a life saver and has so many benefits that it is almost criminal not to leverage it at some point.
I highly recommend learning about the STL. The only book I know for the STL is Effective STL but I cannot really recommend it to you since you are quite new to the STL. That book is really geared towards those that have been using it but want ways to use it more effectively. You might be able to learn how to use the STL from it but that is not the goal of the book.
Perhaps others here could recommend a beginner book for learning the STL.
I was originally iterating through object.str, and incrementing the sizeOfArrayOfPointers only if the current character of the string was not a new-line character. That's not counting new-lines...
Then I realized that wasn't the size that I wanted for the array of pointers, because each pointer is supposed to point at an individual string. And there are three of those...
So I rewrote the code to create the array of pointers with a size of 3, and that's how I have it now.Yes, a string...
Yes, another string...
Yes, even another string...
I do understand how it works, and I also understand that I don't have to point object.anotherStr at a "new" allocation in memory each loop. The reason I did it that way is because my code in my real program also does it that way, and the reason for that is the anotherStr (named differently in my real program) is a member of a class, and I just prefer to do it that way. And, my class destructor takes care of deleting every "new" thing, so no memory leaks there.I love how you are able to use the word "simply" in there. Using that word does not make it true.
What's more, it probably isn't actually doing what you think it's doing. I know this both because your descriptions don't quite make sense and because you've still failed to realise why allocating those strings dynamically does not do anything good for that piece of code. If you understood how it really worked you'd realise this. I've already shown how that unnecessary complication can be avoided in a code example.I mean exactly what anyone else who mentions it means. The mere mention of it to most C++ programmers should immediately put you both into a state of mutual understanding. You don't know about much of the most commonly used stuff in the standard C++ Library and that is most unfortunate for you as your job will be that much harder without it.It makes sense that your description would be as convoluted as your code is. They both come from the same thought process. You need to learn to think about the effect you are trying to achieve at a higher level.
No, it doesn't. I delete all the "new"s at the end of the doStuff() function. And what is wrong with my usage of string::data()? Each element of my array of pointers is being assigned the memory location of each anotherStr->data(), and I don't delete anything until I've outputted the strings contained at those memory locations.Well, what you've ended up with is far from pretty. It has memory leaks and usage of string::data() that is almost certainly going to mean trouble in your real code. Any attempt to return an array of const char *'s along the lines of what you've been doing is pretty much going to guarantee a memory leak or accessing deleted memory.
Do you realise that you have a for-loop there that will never loop? In other words, it's equivalent to just an if-statement.
As for returning a const char* array in my real program, that also is not a problem, because I make sure to only delete with my class destructor.
Yes, and I do appreciate that. And I do plan on learning more of the language. I have a few programming books that I've been planning to read. I am far from being an expert at programming, I know.Well it's all for your own benefit. Perhaps if you get stuck in and learn more about the language you'll come to look back on this code one day and realise how far you've come. If that happens - mission accomplished.
Last edited by Programmer_P; 05-23-2010 at 07:58 PM.
You forgot to use a try/catch block to handle cases where an exception (e.g., std::bad_alloc) is thrown before those delete statements can be reached.Originally Posted by Programmer_P
Look up a C++ Reference and learn How To Ask Questions The Smart WayOriginally Posted by Bjarne Stroustrup (2000-10-14)
Ya know in the time it has taken to build this code and the time that would be wasted for other developers to figure out what in the world you were trying to do you could have used the STL in several places and been done. As well your code would be much clearer to anyone later who was tasked with maintaining and/or integrating your code into a code line.
Programming isn't just about what works.
Not only does your inner for-loop never loop, but your outer one is looping up to the wrong constant.
Here's another leak:You've just thrown away your only pointer to anotherStr. No way to free it now.Code:object.anotherStr = NULL; //reset this pointer
I certainly see why you want to use pointers to strings. It's because you don't want their actual contents to be freed at all, since the app is broken and would cause accessing data after it was freed. Using data() at all is really pushing you into doing bad things. You should really be using .c_str() if you must avoid directly having an array of strings.
There are two ways to write code. Such that:
- there are no obvious bugs, or
- there are obviously no bugs
Many people mistakenly aim for the first one
My homepage
Advice: Take only as directed - If symptoms persist, please see your debugger
Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"
I must confess I am baffled by all this convoluted code to do such a simple task.
You're right. I understand this...
More coding, less posting is what I'll do in the future. Perfect practice of programming will make an almost-perfect programmer. I got it.
Btw, thanks everyone for the support. Hopefully soon once I get really good at programming, it'll be me who's the one providing support for other programmers, not the other way around, though I suppose I'll never know everything there is to know about programming, and will still occasionally need assistance and advice. That's what makes us human.
Well, yes, I obviously noticed that when I first wrote the code (i.e. that the loop would only be entered once), just wasn't thinking as straight as I should have. Guess I should have used an if statement instead. As for the outer loop, I don't really see a problem with that, because once the if statement, and then the inner for loop, is entered, we then just move on from the current index of 'i', wherever 'i' is, and continue iterating through the rest of the string. And then inside the if statement, I delete the stuff I created on the heap, then return out of the function. What would your suggestion be in regards to this? Please post some example code.
You're right. I was thinking that by keeping a pointer to each string with an element of the array of pointers, I could then delete those new objects in memory by doing:Here's another leak:You've just thrown away your only pointer to anotherStr. No way to free it now.Code:object.anotherStr = NULL; //reset this pointer
But I see now where I made my error.Code:delete [] object.arrayOfPointers;
Yep, and I'll shoot for Way #2 next time around.I certainly see why you want to use pointers to strings. It's because you don't want their actual contents to be freed at all, since the app is broken and would cause accessing data after it was freed. Using data() at all is really pushing you into doing bad things. You should really be using .c_str() if you must avoid directly having an array of strings.
There are two ways to write code. Such that:
- there are no obvious bugs, or
- there are obviously no bugs
Many people mistakenly aim for the first one
Last edited by Programmer_P; 05-23-2010 at 08:15 PM.
The task I was trying to achieve was not just to output a few strings. The task was to test working with arrays of pointers, and to see if I could achieve the task of outputting the strings being pointed at by the elements of the array of pointers.
Obviously, I understand now a lot more about arrays of pointers, and also about vectors, and about coding in generally. But fortunately, I managed to sort all of the bugs out eventually, thanks to all y'all's help.
Actually more listening is what I was after. The reason we suggest to you option A or B is b/c we are trying to save you the pain that we have gone through once before trying to do a similar task.More coding, less posting is what I'll do in the future.