Thread: Arrays of pointers...

  1. #31
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by tabstop View Post
    That code doesn't print any memory addresses. It just segfaults, when you try to access NULL the second time through that for loop around line 65.
    Well, it was until I realized that I had accidentally assigned the data of the wrong string to the elements of the array (i.e. object.str->data() instead of object.anotherStr->data after the while loop). I fixed that problem, so now it just seg-faults.

    In mine, there is no line 65. Line 53 is the last for loop of the "doStuff" function, and is the loop which handles outputting object.arraysOfPointers[i]. The for loop before that is at line 43. That's the one which loops while 'i' is less than sizeOfStr (a variable which is assigned the value of object.str->size()). There is no reason why it should be accessing a NULL value.

  2. #32
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by tabstop View Post
    (EDIT: You're not actually accessing NULL -- you started the pointer out at NULL and you've been adding characters to the value of the pointer, so by the time you're done you're at some number in thousands, but that isn't actually a pointer to a string now is it.)
    Not sure if you're right...
    Are you referring to object.str?

    If so, yes, that pointer is initialized to NULL, however before I start adding characters, I first allocate it a "new" spot in memory. Then I de-reference (i.e. access the memory location pointed at by that pointer) and start adding characters to it.
    Code:
    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";
    I next get the size of that string, then loop through it with the first for loop, incrementing the "sizeOfArrayOfPointers" variable value by 1 each loop, while the current character of the string does not equal a '\n' character so as to get the size of the string, minus the new-line characters. I next use that size to create the array of pointers. The second for loop next moves through the str, adding each character to another string (called "anotherStr" for convenience) as long as the current character is not a new-line character. The resulting string pointed at by "object.anotherStr" is next assigned to the current element of the array of pointers (or to put it another way, the current pointer element of the pointer array is assigned the memory address of the anotherStr). This does this as long as i < sizeOfStr. And there we have the problem...

    I should be doing it as long as i < sizeOfArrayOfPointers instead.

    EDIT: Hmm...that made no difference. Still, a seg-fault.

  3. #33
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Ok, I'm done with this for the night. Ridiculous that this took me all day...
    I should have got it working hours ago.

    Oh well, I'll have another go at it tomorrow.

  4. #34
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Programmer_P View Post
    No, actually I just ignored that part, and added an initializer list to initialize the array of pointers to NULL like you have in your posted code a few posts back... So I still followed your advice, just not the statement about no member pointers.

    Do you think that it would output the strings, and not the memory addresses, if I did that though? If not, I wont bother changing it since its just a test program anyway.
    If you're hell bent on using pointers when there is no need, then why is 'object' not declared as a pointer to stringStruct?
    Code:
    stringStruct *object;
    object->str = new string;
    *object->str = "Yes, a string...\n";
    // etc
    delete object;
    Oh and how about sizeOfArrayOfPointer:
    Code:
    int *sizeOfArrayOfPointer;
    sizeOfArrayOfPointer = new int;
    *sizeOfArrayOfPointers = 0;
    // etc
    delete sizeOfArrayOfPointers;
    I mean, you can see why this is redundant and silly right? So how is it that you think declaring pointers to those strings isn't just as redundant?

    I'm going to make assumptions about what your code is meant to be doing and just show you an improvement. I assume you are trying to split the string at the newlines and print out each string from the array of pointers. The following is better, and should achieve your goal. This code is still not ideal, but this is probably not a sensible thing to be doing in the first place.
    Code:
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    struct stringStruct {
      stringStruct() : arrayOfPointers(NULL) {}
      string str;
      const char** arrayOfPointers; // Should really be a vector
      ~stringStruct() { delete [] object.arrayOfPointers; } // Safer to do this here
    private: // Standard code for preventing an object from being copied, follows
      stringStruct(const stringStruct&);
      stringStruct& operator=(const stringStruct&);
    };
    
    void doStuff();
    
    int main(void) {
      doStuff();
      cin.get();
      return 0;
    }
    
    void doStuff() {
      stringStruct object;
      object.str = "Yes, a string...\n"
         "Yes, another string...\n"
         "Yes, even another string...\n"; // You can concatenate string literals more efficiently like this
      int sizeOfStr = object.str.size();
      int numberOfPointers = 0;
      for (int i = 0; i < sizeOfStr; i++) {
         if (object.str.at(i) != '\n') {
            numberOfPointers++;
         } else {
            object.str[i] = '\0'; // We cant output the string later if it isn't null-terminated
            // Also we have to make all modifications prior to calling data(), so it's done here
         }
      }
      object.arrayOfPointers = new const char*[numberOfPointers];
      int i2 = 0;
      for (int i = 0; i < numberOfPointers; i++) {
         object.arrayOfPointers[i] = &object.str.data()[i2];
         while (object.str.at(i2) != '\0)
            i2++;
         i2++;
      }
      for (int i = 0; i < numberOfPointers; i++) {
         cout<< object.arrayOfPointers[i] << endl;
      }
    }
    Your code had several major flaws that meant it could never work as it was, hence the significant changes. E.g. you couldn't cout the pointers obtained from the string's data() because they weren't guaranteed to be null-terminated. There is no place for 'sizeof' in that program.
    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"

  5. #35
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Programmer_P View Post
    Not sure if you're right...
    Are you referring to object.str?

    If so, yes, that pointer is initialized to NULL, however before I start adding characters, I first allocate it a "new" spot in memory. Then I de-reference (i.e. access the memory location pointed at by that pointer) and start adding characters to it.
    Code:
    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";
    I next get the size of that string, then loop through it with the first for loop, incrementing the "sizeOfArrayOfPointers" variable value by 1 each loop, while the current character of the string does not equal a '\n' character so as to get the size of the string, minus the new-line characters. I next use that size to create the array of pointers. The second for loop next moves through the str, adding each character to another string (called "anotherStr" for convenience) as long as the current character is not a new-line character. The resulting string pointed at by "object.anotherStr" is next assigned to the current element of the array of pointers (or to put it another way, the current pointer element of the pointer array is assigned the memory address of the anotherStr). This does this as long as i < sizeOfStr. And there we have the problem...

    I should be doing it as long as i < sizeOfArrayOfPointers instead.

    EDIT: Hmm...that made no difference. Still, a seg-fault.
    This line here:
    Code:
    object.anotherStr += object.str->at(i2);
    You're just adding to the pointer, making it point somewhere else.

  6. #36
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by tabstop View Post
    This line here:
    Code:
    object.anotherStr += object.str->at(i2);
    You're just adding to the pointer, making it point somewhere else.
    You're right, however, even after changing that line to:

    *object.anotherStr += object.str->at(i2);

    instead, it still seg-faults. There shouldn't be a problem, there, even though object.str->at() returns a char reference, because the '+=' operator of the string class can handle a char.

  7. #37
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    What is your current code? Why are you not using a std::vector or other appropriate container?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #38
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by iMalc View Post
    If you're hell bent on using pointers when there is no need, then why is 'object' not declared as a pointer to stringStruct?
    Code:
    stringStruct *object;
    object->str = new string;
    *object->str = "Yes, a string...\n";
    // etc
    delete object;
    Oh and how about sizeOfArrayOfPointer:
    Code:
    int *sizeOfArrayOfPointer;
    sizeOfArrayOfPointer = new int;
    *sizeOfArrayOfPointers = 0;
    // etc
    delete sizeOfArrayOfPointers;
    I mean, you can see why this is redundant and silly right? So how is it that you think declaring pointers to those strings isn't just as redundant?
    Because the point of using an array of pointers to those strings is so I can later return a pointer to the whole array, and be able to easily access each string I want to access (separately), in my real program. If I try using just a normal char array[], for example, then I can only store one continuous string. I could of course separate individual strings inside the normal char array with a character like '\n', but I don't want to do that. I want to have the ability to access each individual string of the array, by simply accessing a specific array index. See, what this real program does is it reads from a file line by line, storing the contents of the line in a char array called "filestreamInBuffer". I then check the contents of that array to see if it contains the string which I'm searching for (i.e. "enum"). If it does, I continue reading lines from that point until the terminating semicolon has been found (or if, for some bizarre reason, it doesn't, and it reaches the end of the file without finding it, I set a bool variable called "terminatingSemicolonDoesNotExist" as true, then break out of the loop). Now, here is where the fun begins...
    Before I find the terminating semicolon, I add each line of the file after the line of which "enum" was found to a string (after first stripping it to contain only the string name of the enum value). I also count how many enum values have been found, so that once all that is done, I can create a new char* array with the size of the number of enum values. I then do something similiar to what I did in the test program, i.e. loop through that string which contains all the enum values, and adding characters to another string so long as the current character is not a new-line character, and then assigning the resulting string to the current index element of the char* array. Once that function has done all the stuff I wrote it to do, I can then retrieve all the bits and pieces of the enum separately (i.e. like the enum name, the names of the enum values as a char* array), and everything's just dandy. The whole point of the real program is so I can easily retrieve the string names of the enum values of any enum.
    Of course, though, it would be nice to get the whole logic of the array of pointers working first...
    I'm going to make assumptions about what your code is meant to be doing and just show you an improvement. I assume you are trying to split the string at the newlines and print out each string from the array of pointers. The following is better, and should achieve your goal. This code is still not ideal, but this is probably not a sensible thing to be doing in the first place.
    You are correct with that assumption. Basically, I want to add individual strings to a string type, separating them with a '\n' character. I then want to loop through that string, and assign each string to the current element of the char* array up until the '\n' character is detected.
    Code:
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    struct stringStruct {
      stringStruct() : arrayOfPointers(NULL) {}
      string str;
      const char** arrayOfPointers; // Should really be a vector
      ~stringStruct() { delete [] object.arrayOfPointers; } // Safer to do this here
    private: // Standard code for preventing an object from being copied, follows
      stringStruct(const stringStruct&);
      stringStruct& operator=(const stringStruct&);
    };
    Well, yes, obviously its best to delete a member variable from inside the class or struct destructor. I know this, but I didn't do it in this test program, because its so small, and I made sure to delete all "new" allocatations inside the "doStuff" function. And of course, I think you mean "delete [] arrayOfPointers;" not "delete [] object.arrayOfPointers" since we're inside the member function destructor, and "object" is a "stringStruct" object created inside the "doStuff" function.
    Code:
    void doStuff();
    
    int main(void) {
      doStuff();
      cin.get();
      return 0;
    }
    
    void doStuff() {
      stringStruct object;
      object.str = "Yes, a string...\n"
         "Yes, another string...\n"
         "Yes, even another string...\n"; // You can concatenate string literals more efficiently like this
      int sizeOfStr = object.str.size();
      int numberOfPointers = 0;
      for (int i = 0; i < sizeOfStr; i++) {
         if (object.str.at(i) != '\n') {
            numberOfPointers++;
         } else {
            object.str[i] = '\0'; // We cant output the string later if it isn't null-terminated
            // Also we have to make all modifications prior to calling data(), so it's done here
         }
      }
      object.arrayOfPointers = new const char*[numberOfPointers];
      int i2 = 0;
      for (int i = 0; i < numberOfPointers; i++) {
         object.arrayOfPointers[i] = &object.str.data()[i2];
         while (object.str.at(i2) != '\0)
            i2++;
         i2++;
      }
      for (int i = 0; i < numberOfPointers; i++) {
         cout<< object.arrayOfPointers[i] << endl;
      }
    }
    Your code had several major flaws that meant it could never work as it was, hence the significant changes. E.g. you couldn't cout the pointers obtained from the string's data() because they weren't guaranteed to be null-terminated. There is no place for 'sizeof' in that program.
    Well, I tried to fix that problem in my new version, however when I do this:
    Code:
    for (int i = 0; i < sizeOfStr; i++) {
        while (object.str->at(i2) != '\n') {
          *object.anotherStr += object.str->at(i2);
          i2++;
        }
        if (i == sizeOfArrayOfPointers - 2) {
            object.arrayOfPointers[i] = object.anotherStr->data();
            *object.arrayOfPointers[i+1] = '\0';
            break; //out of the loop since we're at the last element in the array of pointers
        }
        object.arrayOfPointers[i] = object.anotherStr->data();
        object.anotherStr = NULL; //reset this pointer
      }
    It refuses to compile, because the bolded line is said to be trying to access a "read-only" location, which I guess means the array IS terminated with that character already after all...

    EDIT: Nevermind...I see what you mean. Each character string (which means EVERY string pointed at by each element of the char* array) should be NULL-terminated. I'll get right on that right away..
    Last edited by Programmer_P; 05-22-2010 at 11:34 AM.

  9. #39
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Programmer_P View Post
    You're right, however, even after changing that line to:

    *object.anotherStr += object.str->at(i2);

    instead, it still seg-faults. There shouldn't be a problem, there, even though object.str->at() returns a char reference, because the '+=' operator of the string class can handle a char.
    But you still can't dereference a NULL pointer.

  10. #40
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Programmer_P
    Because the point of using an array of pointers to those strings is so I can later return a pointer to the whole array, and be able to easily access each string I want to access (separately), in my real program. If I try using just a normal char array[], for example, then I can only store one continuous string. I could of course separate individual strings inside the normal char array with a character like '\n', but I don't want to do that. I want to have the ability to access each individual string of the array, by simply accessing a specific array index.
    I would reach for a std::vector<std::string>.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #41
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by laserlight View Post
    What is your current code? Why are you not using a std::vector or other appropriate container?
    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();
      cin.get();
      return 0;
    }
    
    void doStuff() {
      stringStruct object;
      object.str = new string;
      *object.str = "Yes, a string...\n" + '\0';
      *object.str += "Yes, another string...\n" + '\0';
      *object.str += "Yes, even another string...\n" + '\0';
      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++) {
        while (object.str->at(i2) != '\n') {
          *object.anotherStr += object.str->at(i2);
          i2++;
        }
        if (i == sizeOfArrayOfPointers - 1) {
            object.arrayOfPointers[i] = object.anotherStr->data();
            break; //out of the loop since we're at the last element in the array of pointers
        }
        object.arrayOfPointers[i] = object.anotherStr->data();
        object.anotherStr = NULL; //reset this pointer
      }
    
      for (int i = 0; i < sizeOfArrayOfPointers; i++) {
        cout<< object.arrayOfPointers[i] <<endl;
      }
    
      delete object.str;
      delete [] object.arrayOfPointers;
      delete object.anotherStr;
    }
    As to why I'm not using a vector, its because I don't need a resizable array. I only need a fixed-size array which is given a size based on how many individual strings are contained within one string (separated by a '\n' character)...

  12. #42
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Programmer_P
    As to why I'm not using a vector, its because I don't need a resizable array. I only need a fixed-size array which is given a size based on how many individual strings are contained within one string (separated by a '\n' character)...
    It still makes sense to use a vector since the size is not fixed at compile time. If you insist that it does not make sense, then rewrite your code to remove this:
    Code:
    new const char*[sizeOfArrayOfPointers]
    because you don't need it. If you do need it, then you should use a std::vector or other appropriate container.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #43
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by tabstop View Post
    But you still can't dereference a NULL pointer.
    Its not NULL by the time I de-reference. It was assigned a "new" allocation in memory first.

  14. #44
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    You need to start heeding the advice of people on here who know how to do what you want instead of insisting on doing it your way. If you need this for a collection of strings I would recommend, as others here have, a vector of strings.

    A vector of pointers is so much simpler than an array of pointers. Neither one is all that difficult but the latter has some nasty syntax associated with it.

    Quite simply:

    std::vector<Object *> objects;
    Is about the simplest way to maintain pointers to several heterogenous objects.

  15. #45
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Programmer_P View Post
    Its not NULL by the time I de-reference. It was assigned a "new" allocation in memory first.
    You're joking, right? I mean, surely you can see that there is literally no code between
    Code:
    object.anotherStr = NULL; //reset this pointer
    and (the next time through the for loop)
    Code:
    *object.anotherStr += object.str->at(i2);

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Issue with arrays, pointers, and structs.
    By RexInTheCity in forum C Programming
    Replies: 5
    Last Post: 03-29-2010, 03:30 PM
  2. Pointers As 2D arrays
    By TieFighter in forum C Programming
    Replies: 29
    Last Post: 03-22-2010, 06:46 AM
  3. pointers to arrays
    By rakeshkool27 in forum C Programming
    Replies: 1
    Last Post: 01-24-2010, 07:28 AM
  4. Array of Pointers to Arrays
    By Biozero in forum C Programming
    Replies: 2
    Last Post: 04-19-2007, 02:31 PM
  5. Pointers and multi dimensional arrays
    By andrea72 in forum C++ Programming
    Replies: 5
    Last Post: 01-23-2007, 04:49 PM