Anyone have experience with C++ vectors?

NabePup

Est. Contributor
Messages
637
Role
  1. Adult Baby
  2. Diaper Lover
  3. Babyfur
  4. Diaperfur
  5. Little
I'm trying to write a program in C++ that separates a string into its separate elements if it contains multiple elements separated by spaces.

For instance, the string "john hubert williams doe" would be stored as a vector containing the values {"john", "hubert", "williams", "doe"} at indexes 0-3. It works for the first 3 indexes, but then I have trouble accessing any values stored beyond the 2nd index.

Here's the source:
Code:
1    #include <iostream>
2    #include <vector>
3    using namespace std;
4
5
6
7    int main() {
8
9        string client_name;
10       int vector_index = 0;
11       vector<string> names[vector_index];
12
13       cout << "Input a name: ";
14       getline(cin, client_name);
15
16       cout << "Starting iteration through: " << client_name << "\n\n";
17       for (int i = 0; i < client_name.length(); i++)
18      {
19           cout << "Iteration: " << i << endl;
20           string temp_string;
21           cout << "\'" << client_name[i] << "\' is not a space or end. Iterating"
22               << " through valid chars to add to index.\n";
23           while (client_name[i] != ' ' && client_name[i] != 0 )
24           {
25               cout << "Adding \'" << client_name[i] << "\' to temp_string."
26                   << endl;
27               temp_string += client_name[i];
28               i++;
29           }
30           cout << "Assigning \"" << temp_string << "\" to index " <<
31              vector_index << " of names vector.\n";
32           names[vector_index].push_back(temp_string);
33           cout << "Clearing temp_string.\n";
34           temp_string.clear();
35           cout << "New names vector at index " << vector_index << " is \"" << names[vector_index][0] << "\".\n";
36           cout << "Incrementing vector index to " << vector_index + 1 <<
37               "\n\n";
38           vector_index++;
39       }
40
41       cout << "Original input is \"" << client_name << "\"\n";
42       for (int i = 0; i < vector_index; i++)
43       {
44           cout << "Index " << i << " of names vector is \"" << names[i][0] <<
45               "\"\n";
46       }
47
48       return 0;
49   }

I've added some cout statements for debugging purposes. And here's the output I'm getting...

Code:
1    Input a name: word1 word2 word3 word4
2    Starting iteration through: word1 word2 word3 word4
3
4    Iteration: 0
5    'w' is not a space or end. Iterating through valid chars to add to index.
6    Adding 'w' to temp_string.
7    Adding 'o' to temp_string.
8    Adding 'r' to temp_string.
9    Adding 'd' to temp_string.
10   Adding '1' to temp_string.
11   Assigning "word1" to index 0 of names vector.
12   Clearing temp_string.
13   New names vector at index 0 is "word1".
14   Incrementing vector index to 1
15
16   Iteration: 6
17   'w' is not a space or end. Iterating through valid chars to add to index.
18   Adding 'w' to temp_string.
19   Adding 'o' to temp_string.
20   Adding 'r' to temp_string.
21   Adding 'd' to temp_string.
22   Adding '2' to temp_string.
23   Assigning "word2" to index 1 of names vector.
24   Clearing temp_string.
25   New names vector at index 1 is "word2".
26   Incrementing vector index to 2
27
28   Iteration: 12
29   'w' is not a space or end. Iterating through valid chars to add to index.
30   Adding 'w' to temp_string.
31   Adding 'o' to temp_string.
32   Adding 'r' to temp_string.
33   Adding 'd' to temp_string.
34   Adding '3' to temp_string.
35   Assigning "word3" to index 2 of names vector.
36   Clearing temp_string.
37   New names vector at index 2 is "word3".
38   Incrementing vector index to 3
39
40   Iteration: 18
41   'w' is not a space or end. Iterating through valid chars to add to index.
42   Adding 'w' to temp_string.
43   Adding 'o' to temp_string.
44   Adding 'r' to temp_string.
45   Adding 'd' to temp_string.
46   Adding '4' to temp_string.
47   Assigning "word4" to index 3 of names vector.
48   Clearing temp_string.
49   New names vector at index 3 is "word4".
50   Incrementing vector index to 4
51
52   Original input is "word1 word2 word3 word4"
53   Index 0 of names vector is "word1"
54   Index 1 of names vector is "word2"
55   Index 2 of names vector is "word3"
56   Index 3 of names vector is ""q???"q??pVq??"

Anything that's at the 3rd or greater index of the vector is this weird thing whenever I try accessing the data stored there. Yet I have no trouble accessing the data stored at those indexes earlier (one line 49 of the output, it accesses the string "name4" correctly).
 
Last edited:
It looks like your declaration of "names" is trying to declare it as an array of vectors (of type string), but declares it with dimension of 0 (i.e. vector_index). This probably isn't what you want. Writing data into higher indices is writing into undeclared memory, so as things get pushed and popped off the stack, like when you exit the for loop with locally-scoped i and temp_string for instance, those values can get clobbered. Your declaration should look like:

Code:
vector<string> names;

You add strings to it using names.push_back(). You can then cout the list of strings by declaring an iterator for that vector, like this:

Code:
for (vector<string>::iterator i = names.begin(); i != names.end(); i++)

And printing out the dereference of the iterator just like a regular pointer:
Code:
{
int j = 0;
cout << "Index " << j << " of names vector is \"" << *i << "\"\n";
j++;
}

Does that help?
 
Last edited:
OMG

Me love you long time!! :worshippy: lol

I'm getting the results I need now. Originally, I kept getting a conversion error when I tried adding the string to the specific vector index via push_back() and before that I got an error for not having the vector indexed when I initialized it. I can't remember exactly what I was doing when I got that error, but I did find it kinda odd since vector sizes were supposed to be dynamic.

YES..IT HELPED!! THANKYOU!!

- - - Updated - - -

Sapphyre said:
Code:
for (vector<string>::iterator i = names.begin(); i != names.end(); i++)

Soooo, if you don't mind answering...I'm curious as to what this line does exactly? I totally intend to and will learn it the "normal way", researching the heck out of it, playing and experimenting with it, and ultimately grasping it after enough ah-ha and frustrating moments happen. So no worries whatsoever if ya don't feel like answering, it'll take actual experience with it to learn it anyway

But from the looks of it:

'i', an iterator type variable that's referencing a vector of strings is being declared and initialized to the first element of the vector of strings, "names". The for loop will continue as long as 'i' doesn't equal the last element of the vector of strings. And since 'i' is an iterator, when it's incremented it equals the next value of the vector it's referencing?

And 'j' has to be initialized in the loop as a counter since 'i' doesn't actually equal the iteration it's on since it's a pointer to the values of the vector, "names".

Pointers and references, that's one thing I gotta tackle next.
 
TheCaptain said:
OMG

Me love you long time!! :worshippy: lol

I'm getting the results I need now. Originally, I kept getting a conversion error when I tried adding the string to the specific vector index via push_back() and before that I got an error for not having the vector indexed when I initialized it. I can't remember exactly what I was doing when I got that error, but I did find it kinda odd since vector sizes were supposed to be dynamic.

YES..IT HELPED!! THANKYOU!!

- - - Updated - - -



Soooo, if you don't mind answering...I'm curious as to what this line does exactly? I totally intend to and will learn it the "normal way", researching the heck out of it, playing and experimenting with it, and ultimately grasping it after enough ah-ha and frustrating moments happen. So no worries whatsoever if ya don't feel like answering, it'll take actual experience with it to learn it anyway

But from the looks of it:

'i', an iterator type variable that's referencing a vector of strings is being declared and initialized to the first element of the vector of strings, "names". The for loop will continue as long as 'i' doesn't equal the last element of the vector of strings. And since 'i' is an iterator, when it's incremented it equals the next value of the vector it's referencing?

And 'j' has to be initialized in the loop as a counter since 'i' doesn't actually equal the iteration it's on since it's a pointer to the values of the vector, "names".

Pointers and references, that's one thing I gotta tackle next.

You've basically got it. The iterator is an object with its own methods defined, among them an overloaded "++" operator that increments it to the next element in a vector structure. You can think of names.end() as akin to a null terminator at the end of a string or a linked list (which is basically what a vector is anyway). The last element in the list is actually the one just before names.end(). So when the iterator reaches names.end(), we stop.
You are also right that I declared a separate counter "j" because "i" is not an integer index and won't display what you were intending. "j" could have been declared / initialized elsewhere too, I just threw it at the beginning. If you want to get a bit fancier, you could write the loop as

Code:
for(vector<string>::iterator i = names.begin(), int j = 0; i != names.end(); i++, j++)

^_^
 
Yay! Nerd solidarity

This info has been really helpful (both with the specific problem I was facing and with learning a new C++ feature/design). Another step in the right direction :)
I remember messing with vectors before and how if I'm not mistaken, there was always an empty string "" or char ' ' appended one beyond the last assigned index. Kinda like how there's a 0 at the end of a string. I didn't even know all that could be declared in a for loop! I thought it was always the initializer; the loop condition; the increment.
 
TheCaptain said:
Yay! Nerd solidarity

This info has been really helpful (both with the specific problem I was facing and with learning a new C++ feature/design). Another step in the right direction :)
I remember messing with vectors before and how if I'm not mistaken, there was always an empty string "" or char ' ' appended one beyond the last assigned index. Kinda like how there's a 0 at the end of a string. I didn't even know all that could be declared in a for loop! I thought it was always the initializer; the loop condition; the increment.

I'm glad I could help! ^_^

You can have all kinds of fun with loop syntax. ^.^ Check out Duff's Device for a clever way to unroll (optimize) loops, as an example…
 
I've been programming C++ for 17 years now, if you need help or tips I can answer.
I use lists vectors sets tuples and maps heavily.
 
MickeyM said:
I've been programming C++ for 17 years now, if you need help or tips I can answer.
I use lists vectors sets tuples and maps heavily.

Oh boy, you gone done did it now haha. I've got tons of questions and continue to get more, guess it's part of this whole "learning" thing. Right now I've started encountering an issue with a class I'm making. I've been researching it and will probably figure it out at some point, but I'll take and can use any help I can get if you don't mind. I really appreciate it!

Forgive me if I use incorrect terminology. I'm pretty sure what I'm trying to is create a setter function for a class member variable

I have a class called NewClientDirectory.
- it has a public function NewClientDirectory.client_name() that sets a string to the private member variable NewClientDirectory._client_name_raw, making it a getter function, correct?

- it has a public function NewClientDirectory._isolate_names() that splits the NewClientDirectory._client_name_raw member variable delineated by spaces, and assigns each element to each index of the class member variable NewClientDirectory._isolated_names

Now this is the issue I'm facing. Whenever the class is instantiated (an object is created using it), I want the NewClientDirectory._isolate_names() function automatically executed by default so it sets the NewClientDirectory._isolated_names member variable without having to explicitly be called. This would be making NewClientDirectory._isolate_names() a setter, right?

Right now, here's what I got so far:
Code:
#include <vector>
#include <iostream>
using namespace std;

const char UPPER_CASE_LETTERS[26] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
    'X', 'Y', 'Z'};
const char LOWER_CASE_LETTERS[26] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
    'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
    'x', 'y', 'z'};

class NewClientDirectory
{
    public:
        // Getter function that sets _client_name_raw variable.
        void client_name(string);

        // Splits _client_name_raw delineated by spaces and assigns each
        // element to an index of _isolated_names.
        void _isolate_names();

        // Elements of _client_name_raw after being split.
        vector<string> _isolated_names;

    private:
        // Initial raw input received from user.
        string _client_name_raw;

};

// Getter function that sets NewClientDirectory._client_name_raw
void NewClientDirectory::client_name(string name) {  _client_name_raw = name; }

// Setter function that sets NewClientDirectory._isolated_names
void NewClientDirectory::_isolate_names()
{
    // Container to add the strings of _client_name_raw to after splitting it.
    vector<string> names;

    // Iterate through each char of the _client_name_raw member variable.
    for (int i = 0; i < _client_name_raw.length(); i++)
    {
        // Create temporary string to hold chars of _client_name_raw member variable.
        string temp_string;
        // While char isn't a space or terminator...
        while (_client_name_raw[i] != ' ' && _client_name_raw[i] != '\0')
        {
            cout << "Adding \'" << _client_name_raw[i] << "\' to index "
                << i << " of temp_sring\n";
            // Append char to temporary string.
            temp_string += _client_name_raw[i];
            i++;
        }

        // If temp_string isn't empty, add it to names vector.
        if (temp_string != "")
        {
            cout << "Adding " << temp_string << " to names vector." <<
                "\n\n";
            // Add temporary string to vector once the char is a space
            // or terminator
            names.push_back(temp_string);
        }
        // Clear the temporary string so it can be empty for next
        // iteration when chars are added to it.
        temp_string.clear();
    }

    // Assign vector containing separated name strings to class member.
    _isolated_names = names;
}


// Printing output to console for debugging purposes.
int main()
{
    NewClientDirectory obj;
    obj.client_name("john h doe");

    // This needs to be a private member function that is automatically called
    // when NewClientDirectory class is instantiated. It's currently public
    // for debugging purposes.
    obj._isolate_names();

    // Checking elements of _isolated_names member variable. This variable is
    // set by the _isolate_names() member function. _isolated_names will also
    // be private but is currently public for debugging purposes.
    for (int i = 0; i < 3; i++)
    {
        cout << obj._isolated_names[i] << endl;
    }

    return 0;
}

Lemme know if you need me to clarify anything or if this doesn't make any sense. I honestly don't think I could explain my source much clearer, but I also don't see how anyone could understand this either lol
 
Last edited:
Think a "constructor" might be what I need?
 
Last edited:
TheCaptain said:
Think a "constructor" might be what I need?

You guessed it! ^.^
 
TheCaptain said:
Think a "constructor" might be what I need?

I made some modifications here, with some comments in there to explain some other stuff. I'm sure you probably figured out your problem already though.

Code:
#include <vector>
#include <iostream>
#include <string>//--include for std::string
using namespace std;

const char UPPER_CASE_LETTERS[26] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
    'X', 'Y', 'Z'};
const char LOWER_CASE_LETTERS[26] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
    'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
    'x', 'y', 'z'};

class NewClientDirectory
{
    public:
        // Getter function that sets _client_name_raw variable.
        //-- This is a setter function. A getter function returns a value
        void client_name(string&);

        // Splits _client_name_raw delineated by spaces and assigns each
        // element to an index of _isolated_names.
        void _isolate_names();

        // Elements of _client_name_raw after being split.
        vector<string> _isolated_names;
        NewClientDirectory(string);

    private:
        // Initial raw input received from user.
        string _client_name_raw;

};

// Getter function that sets NewClientDirectory._client_name_raw
// -- use references& to optimize execution. no need to initiate a string when unneccesary
void NewClientDirectory::client_name(string& name) {  _client_name_raw.assign(name); }

// Setter function that sets NewClientDirectory._isolated_names
void NewClientDirectory::_isolate_names()
{
    // Container to add the strings of _client_name_raw to after splitting it.
    vector<string> names;

    // Iterate through each char of the _client_name_raw member variable.
    //-- _client_name_raw.length() called unneccesarily each iteration on the loop
    //-- length is type size_t (in most compilers)
    size_t client_name_length = _client_name_raw.length();
    for (size_t i = 0; i < client_name_length; i++)
    {
        // Create temporary string to hold chars of _client_name_raw member variable.
        string temp_string;
        // While char isn't a space or terminator...
        while (_client_name_raw[i] != ' ' && _client_name_raw[i] != '\0')
        {
            //-- if this is debug, suggest using preprocessor #define _DEBUG then here, #ifdef _DEBUG #endif statement surrounding the output
            cout << "Adding \'" << _client_name_raw[i] << "\' to index "
                << i << " of temp_sring\n";
            // Append char to temporary string.
            temp_string += _client_name_raw[i];
            i++;
        }

        // If temp_string isn't empty, add it to names vector.
        if (temp_string != "")
        {
            //-- if this is debug, suggest using preprocessor #define _DEBUG then here, #ifdef _DEBUG #endif statement surrounding the output
            cout << "Adding " << temp_string << " to names vector." <<
                "\n\n";
            // Add temporary string to vector once the char is a space
            // or terminator
            names.push_back(temp_string);//you could do _isolated_names.clear() first in this function and push_back directly to _isolated_names.
        }
        // Clear the temporary string so it can be empty for next
        // iteration when chars are added to it.
        //-- this is not needed. the next loop, temp_string goes out of scope and a new one is created.
        //temp_string.clear();
    }

    // Assign vector containing separated name strings to class member.
    _isolated_names = names;
}

NewClientDirectory::NewClientDirectory(string name)
    {
        client_name(name);
        _isolate_names();
    }

// Printing output to console for debugging purposes.
int main(int argc, char* argv[])
{
    //-- use the constructor
    NewClientDirectory obj("john h doe");
    //obj.client_name("john h doe");

    // This needs to be a private member function that is automatically called
    // when NewClientDirectory class is instantiated. It's currently public
    // for debugging purposes.
    //obj._isolate_names();

    // Checking elements of _isolated_names member variable. This variable is
    // set by the _isolate_names() member function. _isolated_names will also
    // be private but is currently public for debugging purposes.
    //-- your getter function for this could return a vector copy, or a reference if you live on the edge.
    for (int i = 0; i < 3; i++)
    {
        cout << obj._isolated_names[i] << endl;
    }

    return 0;
}
 
Thanks so much for the input and lil code review :)

I'm just getting a chance to go over it now. Pointers and references scare me jk hehe. I just don't fully understand how to utilize them yet, but I at least sorta understand what they are to an extent. A reference is the address of data in memory and a pointer is the data itself, seems simple enough, but implementing them hasn't completely clicked with me yet. I know that's one of the unique and strongest features of C++ and C (for pointers) and I'm really doing myself a disservice by not using them

I hate to admit it, but I haven't figured the problem out yet :( . So this is all really helpful :thumbsup:
 
C++ is far too fancy for me, plain old C here and lord knows that can get you in more than enough trouble.
 
RubberJin said:
C++ is far too fancy for me, plain old C here and lord knows that can get you in more than enough trouble.

I figured learning C++ would also teach me C in the process, so it'd be killing two birds with one stone. Plus C++ has some nifty features and that's what they teach in most classes. But omg, because of all its features it has the nuttiest syntax haha. Plus it's almost like a hacked C so it can be C that's more oop-ish


Sent from my iPhone using Tapatalk
 
Code:
#include <vector>
#include <iostream>
#include <string>//--include for std::string
using namespace std;


class NewClientDirectory
{
    public:
        NewClientDirectory(string);

};


NewClientDirectory::NewClientDirectory(string name)
    {
        client_name(name);
        _isolate_names();
    }
}

Just to make sure I'm getting this straight, which I think I am. Above is the constructor. By declaring
Code:
NewClientDirectory(string)

in the class' public space, that makes it so the class itself can take an argument (of type string). Then by defining

Code:
NewClientDirectory::NewClientDirectory(string name)
    {
        client_name(name);
        _isolate_names();
    }

that dictates what happens when the class is instantiated. So the argument that's passed to the class, is then processed through the client_name() setter function and then _isolate_names() is executed?

Thanks for bringing up the size_t type and debug preprocessor. I've seen size_t around here and there and had no idea what it was and after just using and messing around with Python's logger module, I figured and assumed there was something similar in c++. It was really helpful in my Python script so it'll be nice to mimic that behavior

That's interesting declaring the iterator variable as type size_t, I'm guessing keeping it as int would probably yield the same results, but if it's being compared and used with size_t type data, then I suppose it makes sense to have it declared as such as well since it'll have to be that type in this instance
 
Last edited:
TheCaptain said:
Thanks so much for the input and lil code review :)

I'm just getting a chance to go over it now. Pointers and references scare me jk hehe. I just don't fully understand how to utilize them yet, but I at least sorta understand what they are to an extent. A reference is the address of data in memory and a pointer is the data itself, seems simple enough, but implementing them hasn't completely clicked with me yet. I know that's one of the unique and strongest features of C++ and C (for pointers) and I'm really doing myself a disservice by not using them

I hate to admit it, but I haven't figured the problem out yet :( . So this is all really helpful :thumbsup:

A pointer is the memory address to the data for a variable.
A reference is an alias for another variable.

int a = 1;
int& b = a;

b IS a.

In otherwords, it works just like assigning variables in java, if you know java..

int a = 1;
int* b = &a;

b holds a pointer to a, you can pass it around as you would any integer value, b, or de-reference it with the * operator, a+*b = 2;

You can get away without using pointers anywhere in a C++ program. Everyone I talk to that doesn't do C++, complains about memory management and pointers -- Just don't use them, you don't *have* to! Use STL containers like vector, string, etc these manage their memory on their own. You seem to already be doing that.

If your comparing two values like is counter < size, you generally want them to be the same type, though C++ does conversions when possible. size_t is just an int.
 
MickeyM said:
A pointer is the memory address to the data for a variable.
A reference is an alias for another variable.

int a = 1;
int& b = a;

b IS a.

In otherwords, it works just like assigning variables in java, if you know java..

int a = 1;
int* b = &a;

b holds a pointer to a, you can pass it around as you would any integer value, b, or de-reference it with the * operator, a+*b = 2;

You can get away without using pointers anywhere in a C++ program. Everyone I talk to that doesn't do C++, complains about memory management and pointers -- Just don't use them, you don't *have* to! Use STL containers like vector, string, etc these manage their memory on their own. You seem to already be doing that.

If your comparing two values like is counter < size, you generally want them to be the same type, though C++ does conversions when possible. size_t is just an int.

Thanks for the lil pointer/reference breakdown. That's the thing about using them, I don't fully see a reason to use them yet and there's usually built in methods and libraries that makes them unnecessary! haha
I know it's probably because I don't fully understand the application and benefits of using them AAAAND none of my little programs require anywhere near the performance where manual memory management is necessary. I still want to learn about them though none the less otherwise I feel that'd be missing out on being able to leverage one of the major benefits of c++ plus understanding it couldn't hurt.

I've recently started checking out passing arguments by reference to functions. It's nice being able to "share" data between functions that way.

I've also started fooling around with structs (with dynamically sized arrays in mind specifically) and OMG! It seems like so much work and effort to do something that's conceptually so simple! I guess after messing with vectors and Python, I've spoiled myself lol. Plus my lack of experience with pointers is starting to become much more apparent now :sweatdrop:hehe
 
Pointers are brilliant, but with great power and all that...

I do embedded stuff so even C++ is a bit high-level, you need to know what's going on sometimes down to the CPU cycle.
 
RubberJin said:
Pointers are brilliant, but with great power and all that...

I do embedded stuff so even C++ is a bit high-level, you need to know what's going on sometimes down to the CPU cycle.

Way way waaaaayy down the line I wanna check out Assembly at some point. But I have a feeling I'm definitely nowhere near ready to take on another language, but also mainly it wouldn't be beneficial for getting into the programming industry compared to a higher level language. Heck, I feel c++ is probably too low level and specialized of a language for at least starting out (for what I'm looking for at least).

I do like knowing what's going on near the metal. Ultimately it all comes down to boolean logic which anyone with half a brain can grasp. I mean, shopping for groceries or driving usually requires much more sophisticated logic than true or false which every digital action can be reduced to. I think that's pretty cool imo


Sent from my iPhone using Tapatalk
 
Check out NAND2TETRIS for a really good stack-up / explanation.

I find it weird that people can do programming without understanding how a CPU works / a little bit of assembler. Does explain a lot of the posts on StackOverflow though...
 
Back
Top