结构体向量的初始化

97

我想知道如何使用push_back方法将值添加到我的结构体向量中。

struct subject
{
  string name;
  int marks;
  int credits;
};


vector<subject> sub;

那么现在我该如何向其中添加元素呢?

我有一个函数,用于初始化字符串名称(主题名称)。

void setName(string s1, string s2, ...... string s6)
{
   // how can i set name too sub[0].name= "english", sub[1].name = "math" etc

  sub[0].name = s1 // gives segmentation fault; so how do I use push_back method?

  sub.name.push_back(s1);
  sub.name.push_back(s2);
  sub.name.push_back(s3);
  sub.name.push_back(s4);

  sub.name.push_back(s6);

}

函数调用

setName("english", "math", "physics" ... "economics");

1
其他向量初始化的方法:https://dev59.com/11HTa4cB1Zd3GeqPU88L - jpalecek
嘿,我添加了一个新答案,请查看。 - Onk_r
5个回答

121

创建向量,使用push_back添加元素,然后进行修改:

struct subject {
    string name;
    int marks;
    int credits;
};


int main() {
    vector<subject> sub;

    //Push back new subject created with default constructor.
    sub.push_back(subject());

    //Vector now has 1 element @ index 0, so modify it.
    sub[0].name = "english";

    //Add a new element if you want another:
    sub.push_back(subject());

    //Modify its name and marks.
    sub[1].name = "math";
    sub[1].marks = 90;
}

在向量中,只有在该索引处存在元素时,才能使用[#]访问向量。以下示例先填充[#],然后再对其进行修改。


2
subject.resize(2); 可能是一个稍微更快更清晰的解决方案... 或者甚至是 vector<subject> sub(2); - Kerrek SB
1
是的,我同意。 :) 我认为他可能不太理解过度分配以提高效率以及向量如何增长的问题 - 这更像是一个C++入门问题。 - John Humphreys
1
@w00te,我添加了你可能忘记添加的几个引号。希望没问题。 - Natan Streppel
2
@nims 一切都好! :) 我很惊讶这个错误在一个有25,000次浏览的问题上挂了3年,哈哈。 - John Humphreys

70

如果你想使用最新的标准,可以这样做:

sub.emplace_back ("Math", 70, 0); // requires a fitting constructor, though
或者
sub.push_back ({"Math", 70, 0}); // works without constructor

.


5
你的回答的第一部分不准确;如果没有匹配的构造函数,就不能使用emplace_back插入结构体。 - Jean-Simon Brochu
@Jean-SimonBrochu:抱歉稍微晚了一点回复。是的,你说得对,更准确地说,它是特别“不完整”的 :) 我添加了一个澄清者。 - Sebastian Mach

24

你还可以使用大括号初始化列表的聚合初始化方式来处理这类情况。

#include <vector>
using namespace std;

struct subject {
    string name;
    int    marks;
    int    credits;
};

int main() {
    vector<subject> sub {
      {"english", 10, 0},
      {"math"   , 20, 5}
    };
}

有时候,结构体的成员可能并不那么简单,因此您必须在推断其类型方面帮助编译器。

因此,在上述基础上进行扩展。

#include <vector>
using namespace std;

struct assessment {
    int   points;
    int   total;
    float percentage;
};

struct subject {
    string name;
    int    marks;
    int    credits;
    vector<assessment> assessments;
};

int main() {
    vector<subject> sub {
      {"english", 10, 0, {
                             assessment{1,3,0.33f},
                             assessment{2,3,0.66f},
                             assessment{3,3,1.00f}
                         }},
      {"math"   , 20, 5, {
                             assessment{2,4,0.50f}
                         }}
    };
}

如果在大括号初始化程序中没有加上assessment,编译器会在尝试推断类型时失败。

以上内容已经使用c++17在gcc中进行了编译和测试。然而,在c++11及以后的版本中应该也可以工作。在c++20中,我们可能会看到指示符语法,我的希望是它将允许以下内容:

  {"english", 10, 0, .assessments{
                         {1,3,0.33f},
                         {2,3,0.66f},
                         {3,3,1.00f}
                     }},

来源:http://en.cppreference.com/w/cpp/language/aggregate_initialization


14

如果您使用下标操作符[]来访问一个空向量的元素将会失败。
在使用std::vector[]操作符时,确保向量不为空且索引有效。
[]操作符不会添加元素,但如果索引无效,则会导致未定义行为

您应该创建一个结构体的临时对象,填充它,然后使用vector::push_back()将其添加到向量中。

subject subObj;
subObj.name = s1;
sub.push_back(subObj);

4

在查看了已接受的答案后,我意识到如果知道所需向量的大小,则必须使用循环来初始化每个元素

但是,我发现可以使用default_structure_element来完成此操作,如下所示...

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

typedef struct subject {
  string name;
  int marks;
  int credits;
}subject;

int main(){
  subject default_subject;
  default_subject.name="NONE";
  default_subject.marks = 0;
  default_subject.credits = 0;

  vector <subject> sub(10,default_subject);         // default_subject to initialize

  //to check is it initialised
  for(ll i=0;i<sub.size();i++) {
    cout << sub[i].name << " " << sub[i].marks << " " << sub[i].credits << endl;
  } 
}

那么我认为初始化一个结构体的向量是一种不错的方式,不是吗?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接