0

I am trying to use vector of structs for my need, and was writing some sample test code to understand the behavior. Below is the test code I have written:

test.h

struct Student {
  char *name;
  int id;
  char *section;
};
typedef struct Student student_t;

test.cc

#include <iostream>
#include <vector>
#include "test.h"

using namespace std;

int main() {
  vector<student_t> vst;
  //vst.resize(2);
  student_t st;
  st.name = "student1";
  st.id = 4503;
  st.section = "secA";
  vst.push_back(st);
  vst.push_back({"student2", 4504, "secA"});
  for(auto const& s:vst) {
    std::cout<< " student: " << std::endl;
    std::cout << "Name : " << s.name <<
        std::cout << " Id : " << s.id <<
        std::cout << " Section : " << s.section << std::endl;
  }

  return 0;
}

Output without specifying the size of the vector:

student: 
 Name : student10x6040c8 Id : 45030x6040c8 Section : secA
student: 
 Name : student20x6040c8 Id : 45040x6040c8 Section : secA

When resize(2) is used:

student: 
 Name : 

I can't figure out the issue! Is there a problem with my initialization?

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
asundark
  • 3
  • 1
  • 2
    Welcome to Stack Overflow. Please take the time to read [The Tour](http://stackoverflow.com/tour) and refer to the material from the [Help Center](http://stackoverflow.com/help/asking) what and how you can ask here. – πάντα ῥεῖ Jun 27 '17 at 08:43
  • 2
    The right tool to solve such problems is your debugger. You should step through your code line-by-line *before* asking on Stack Overflow. For more help, please read [How to debug small programs (by Eric Lippert)](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). At a minimum, you should [edit] your question to include a [Minimal, Complete, and Verifiable](http://stackoverflow.com/help/mcve) example that reproduces your problem, along with the observations you made in the debugger. – πάντα ῥεῖ Jun 27 '17 at 08:43
  • With `resize` you actually *resizes* the vector. After the call it will be a vector of two default-constructed structures. When you then call `push_back` twice you *add* two more elements to the vector, making its size `4`. Printing out the first two default-constructed elements will of course give you unexpected results, as the pointers will be null-pointers. If you want to *reserve* space for two elements use [`reserve`](http://en.cppreference.com/w/cpp/container/vector/reserve) instead. – Some programmer dude Jun 27 '17 at 08:47
  • 3
    `typedef struct Student student_t;` is a Cism, as is using `char *` to store strings. To familiarise yourself with a more C++y style, you might want to grab a [good C++ book](https://stackoverflow.com/q/388242/1782465). – Angew is no longer proud of SO Jun 27 '17 at 08:55
  • Thanks for your insights. I intend to share the structure file with some existing C code and that's the reason why I couldn't use a string in place of char *. – asundark Jun 27 '17 at 08:57

3 Answers3

3

There are multiple issues with your code. The primary one is that your're printing std::cout to std::cout. Your print expression has this (line breaks omitted to make it obvious):

std::cout << << "Name : " << s.name << std::cout

This is presumably not what you intended, and is what causes the numbers 0x6040c8 to appear in your output (it's probably the address of std::cout).


Another thing is your use of resize. If you use it, you will get a vector with two Student objects in it, which were default constructed. Since you don't provide a reasonable default constructor for your Student class, the values of its non-class members will be essentially random grarbage (and reading them is Undefined Behaviour).

The last issue is that your class has char * members without following the Rule of Three. This works in your example where the members are initialised from string literals (except you have const issues), but could break spectacularly if you later store some dynamically allocated memory in them.

The remedy for these two is one and the same: change the members to be of type std::string, which has both reasonable default initialisation and copy functionality.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
2

The problem is the code:

   std::cout << "Name : " << s.name <<
        std::cout << " Id : " << s.id <<

If you remove the line break, we obtain:

   std::cout << "Name : " << s.name << std::cout << " Id : " << s.id <<

Err, why are you trying to print std::cout on std::cout? Either change the trailing << to ; or:

   std::cout << "Name : " << s.name
             << " Id : " << s.id
   ...

Aside: You are storing up all sorts of trouble for yourself by making name and section be char *. It works at the moment because you are setting them to string literals (which uses a deprecated conversion). As soon as you try and make them variable, you will have to handle allocating and deallocating them. Just save yourself all the grief and make them std::string and be happy.

  • Ah, I didn't realize I was using << in place of ; even after looking at my code for a long time! Thanks for pointing out! :) – asundark Jun 27 '17 at 08:53
  • 3
    If you had stepped through with the debugger, you would have seen the call to `operator <<()` with `std::cout` as the argument - and at that point you would have kicked yourself. – Martin Bonner supports Monica Jun 27 '17 at 08:55
2

Code seems to be correct the thing I found weird is use of char* when you can use std::string

Also, the problem seems to be with the output i.e

std::cout << "Name : " << s.name <<
std::cout << " Id : " << s.id <<
std::cout << " Section : " << s.section << std::endl;

You're printing std::cout inside std::cout which is insane!

std::cout << "Name : " << s.name;
std::cout << " Id : " << s.id;
std::cout << " Section : " << s.section << std::endl;

You see, you missed the big time ;. Welcome to C++!

I'd recommend you to start using debugger gdb if you are a Linux guy, I'll be a big-time help to such problems.

CocoCrisp
  • 807
  • 1
  • 9
  • 26