【问题标题】:inserting struct pointer to vector将结构指针插入向量
【发布时间】:2021-08-09 09:00:07
【问题描述】:

我正在尝试使用vector 创建一个结构指针列表。我的结构包含一些字段,如

#include<stdio.h>
#include<stdlib.h>
#include<vector>
#define MAX 100

struct Student {
    char* name,
    *phoneNum,
    *address
};

我有一个实用函数可以帮助初始化结构指针

struct Student* newStudent() {
    struct Student* pStudent = NULL;
    pStudent = (struct Student*)malloc(sizeof(struct Student));
    pStudent->name = (char*)malloc(MAX * sizeof(char));
    pStudent->phoneNum = (char*)malloc(MAX * sizeof(char));
    pStudent->address = (char*)malloc(MAX * sizeof(char));
  
    return pStudent;
}

插入函数就像

void insert(vector<Student*> &listStudents, Student* pStudent) {
    printf("name: "); scanf("%s\n" , pStudent->name);
    printf("phone number: "); scanf("%s\n", pStudent->phoneNum);
    printf("address: "); scanf("%s\n", pStudent->address);
    listStudents.push_back(pStudent);
    printf("inserted OK!\n");
    printf("Size: %lu\n", listStudents.size());
}

及显示功能

void display(vector<Student*>& listStudents) {
    printf("total students: %lu\n", listStudents.size());
    for (int i = 0; i < listStudents.size(); i++) {
        printf("Student %d\n", i+1);
        printf("name: %s\n", listStudents[i]->name);
        printf("phone number: %s\n", listStudents[i]->phoneNum);
        printf("address %s\n", listStudents[i]->address);
    } 
}

这是我的主要功能

int main() {
   
   Student* pStudent = newStudent();
   vector<Student*> listStudents;
   while(true) {
        int op1;
        printf("\n1. input\n2. output\n3. search\n4. erase\n5. end\n");
        printf("option: "); 
        scanf("%d", &op1);
        switch(op1) {
            case 1:
                insert(listStudents, pStudent);
                break;
            case 2:
                display(listStudents);
                break;
            default:
                printf("invalid option!\n");
                break;
        }
    }
    
    free(pStudent);
}

当我尝试在每个字段中插入一些信息时。这很好。但是当我展示它时 出去。结果重复。例如:

insert:

Student 1:
name: A
phone number: 010...
address: xyz

Student 2:
name: B 
phone number: 011...
address: zyz 

display 结果是

Student 1:
name: B 
phone number: 011...
address: zyz 

Student 2:
name: B 
phone number: 011...
address: zyz 

这有什么问题??

【问题讨论】:

  • insert 只是将参数提供的学生对象指针推入向量中。您在每次迭代中传递 same 对象指针,并在此过程中更改其 content。结果,您的向量被 (a) 反复重复的相同指针填充,并且 (b) 指向的对象包含 last 读取的任何内容。为什么你在其中混搭 C 和 C++ 概念是一个更大的谜。
  • 考虑一下,自从对 newStudent() 的调用发生一次后,您的代码中创建了多少 Student 对象。
  • 如果您使用 C++ 作为向量,为什么不能对 Student 结构使用正确的 C++。也就是说,一个构造函数,new 代替 malloc,或者更好的是,只使用 std::string 而不是 char* 。更不用说cout 而不是printf。您将节省许多代码行...
  • 那有什么问题?? 你把 c++ 和 c 混合起来弄得一团糟。为什么....?

标签: c++ vector struct


【解决方案1】:

你的问题是你有一个学生类的实例,你写了它。在 C++ 中,类通常具有值语义。你通常不会管理自己的记忆。这是一个更惯用的实现:

#include <iostream>
#include <string>
#include <vector>

class Student final {
 private:
  std::string m_name;
  std::string m_phoneNum;
  std::string m_address;

 public:
  Student(std::string name, std::string phoneNum, std::string address)
      : m_name(std::move(name)),
        m_phoneNum(std::move(phoneNum)),
        m_address(std::move(address)) {}

  auto& Name() const noexcept { return m_name; }

  auto& PhoneNumber() const noexcept { return m_phoneNum; }

  auto& Address() const noexcept { return m_address; }
};

Student GetStudent() {
  std::string name, num, addr;
  std::cout << "Name: ";
  std::cin >> name;
  std::cout << "Phone nnumber: ";
  std::cin >> num;
  std::cout << "Address: ";
  std::cin >> addr;
  Student st(std::move(name), std::move(num), std::move(addr));
  return st;
}

int main() {
  std::cin.exceptions(std::istream::failbit | std::istream::badbit);

  std::vector<Student> vec;
  vec.push_back(GetStudent());
  vec.push_back(GetStudent());
  vec.push_back(GetStudent());

  for (auto const& elm : vec) {
    std::cout << "Name: " << elm.Name() << "\nPhone: " << elm.PhoneNumber()
              << "\nAddress: " << elm.Address() << '\n';
  }
}

这也解决了许多其他错误:

  • 您的scanf 调用可能会出现缓冲区溢出
  • lu 不是 size_t 的正确说明符
  • 你泄露了字符串成员(全部)
  • malloc 之后,您不检查nullptr
  • 您的代码不是异常安全的
  • printf 应该被显式刷新,或者你应该在调用 scanf 之前以 '\n' 结束它。

可能还有更多。

【讨论】:

  • 感谢您的评论!我有一个关于使用类的想法。但我只是想试试struct pointer 看看它是如何工作的。
  • @KeinKeinKein 可以让它工作。只是更难。
  • 是的,上面的人只是指出了我的错误,即我对每个插入数据都使用了重复的结构指针。所以打印出来的结果是一样的。但无论如何,谢谢你!
  • @KeinKeinKein 以“C 方式”做这件事本身并不坏。只是更加困难。你必须跟踪许多小事,所有这些指针,如果你弄错了,它就会默默地失败。如果你在“++ Land”,你不妨用 C++ 的方式来做。否则,您可以使用 C 语言开始。我确实指出了您实施中的许多错误。
【解决方案2】:

正如@WhozCraig 在他的评论中提到的,您正在更改相同的结构指针。您必须每次分配不同的结构指针。你的 main 函数应该是这样的,

int main() {
   vector<Student*> listStudents;
   while(true) {
        int op1;
        printf("\n1. input\n2. output\n3. search\n4. erase\n5. end\n");
        printf("option: "); 
        scanf("%d", &op1);
        switch(op1) {
            case 1: {
                Student* pStudent = newStudent();
                insert(listStudents, pStudent);
                break;
            }
            case 2:
                display(listStudents);
                break;
            default:
                printf("invalid option!\n");
                break;
        }
    }
    
    for (const auto& pointers: listStudents)
        free(pointers)
}

每次用户输入 1 时,你必须分配一个新的结构指针。

【讨论】:

  • @感谢您的评论!但是把对象放在switch's case like above cause 里面会导致“交叉初始化错误”。
  • 好的。所以会有另一个编辑。我将编辑和修复代码。
  • 不不会出错,因为变量的作用域是局部的。
猜你喜欢
  • 2012-02-07
  • 1970-01-01
  • 2018-08-28
  • 1970-01-01
  • 2020-11-02
  • 1970-01-01
  • 2013-01-21
  • 1970-01-01
相关资源
最近更新 更多