【问题标题】:C/C++ Remove Item From Struct ArrayC/C++ 从结构数组中删除项目
【发布时间】:2021-09-07 08:58:50
【问题描述】:
struct Student
{
    char* name;
    int balls;
};

void inputdata(Student **s, int *n)
{
    int nn;
    printf("%s\n", "Input amount of students");
    scanf("%i", &nn);
    Student* a = new Student[nn];
    for (int i = 0; i < nn; ++i)
    {
        a[i].name = new char[4096];
        scanf("%4095s", a[i].name);
        scanf("%i", &a[i].balls);
    }
    *n = nn;
    *s = a;
}

void print(Student *s, int n)
{
    for (int i = 0; i < n; ++i)
    {
        printf("%s %i\n", s[i].name, s[i].balls);
    }
}

void fixdata(Student *s, int *n)
{
    int nn = *n;
    for (int i = 0; i < nn; ++i)
    {
        if (s[i].balls > 100)
            s[i].balls = 100;
        else if (s[i].balls < 20)
        {
            for(int j = i; j < nn; ++j)
                s[j] = s[j+1];
            nn-=1;
        }
    }
    *n = nn;
}

int main(int argc, char const *argv[])
{
    Student* s;
    int n;
    inputdata(&s, &n);
    print(s, n);
    fixdata(s, &n);
    print(s, n);
    return 0;
}

我正在尝试删除 balls 小于 20 的项目。如果是这样,我应该将项目向右移动,但同时删除小于 20 的项目。我尝试了,但它彻底向左移动 2 条相同的记录并且没有正确完成工作。

更新: 好的,我清理了一下代码,现在n 减少了,但是当它停留在 1 条记录时的问题,应该也被删除了。我想知道为什么它没有被删除。谢天谢地,大部分问题都解决了。不过,当剩下的一项少于 20 时,删除一项有什么问题?

【问题讨论】:

  • 当一个元素被移除时,你必须改变数组中元素的数量。
  • int balls; - 您可能需要重新考虑这个变量名。你是说score 还是mark
  • 旁注:这段代码非常繁重。我看不出在为 C++ 编译时会有什么不同,但你应该检查你的参考资料,也许在你进入行业之前获得一些专门针对 C++ 及其习语的资料,以便更顺利地进入劳动力市场。跨度>
  • 更严肃的一点是,除非您正在处理家庭作业的需求,否则您不应该使用char* 来存储运行时字符串。使用std::string。您的自制阵列也是如此。另外,考虑使用 C++ 流 IO(std::cinstd::cout)而不是 C 风格的 prrintfscanf
  • prrintf 太棒了!

标签: c++ arrays for-loop dynamic-memory-allocation function-definition


【解决方案1】:

fixdata() 中,当“删除”一个项目时,您会泄漏该项目的name,但更重要的是,如果“最后一个”项目被删除,您的内部循环就会超出数组的范围。

试试这个:

void fixdata(Student *s, int *n)
{
    int nn = *n;
    for (int i = 0; i < nn; ++i)
    {
        if (s[i].balls > 100)
        {
            s[i].balls = 100;
        }
        else if (s[i].balls < 20)
        {
            for(int j = i + 1; j < nn; ++j)
            {
                delete[] s[j-1].name;
                s[j-1] = s[j];
                s[j] = Student{};
            }
            --nn;
        }
    }
    *n = nn;
}

话虽如此,您的代码更像是 C 而不是 C++。 C++ 方法是使用 std::cinstd::stringstd::vector 之类的东西,例如:

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

struct Student
{
    std::string name;
    int balls;
};

std::istream& operator>>(std::istream &in, Student &stud)
{
    in >> s.name >> s.balls;
    return in;
}

std::ostream& operator<<(std::ostream &out, const Student &stud)
{
    out << stud.name << " " << stud.balls;
    return out;
}

void inputdata(std:vector<Student> &s)
{
    int nn;
    std::cout << "Input amount of students\n";
    std::cin >> nn;
    std::vector<Student> a(nn);
    for (auto &stud : s) {
        std::cin >> stud;
    }
    s = std:move(a);
}

void print(const std::vector<Student> &s)
{
    for (const auto &stud : s) {
        std::cout << stud << "\n";
    }
}

void fixdata(std::vector<Student> &s)
{
    for (size_t i = 0; i < s.size();)
    {
        auto &stud = s[i];
        if (stud.balls < 20) {
            s.erase(s.begin()+i);
        }
        else {
            if (stud.balls > 100) {
                stud.balls = 100;
            }
            ++i;
        }
    }
    /* alternatively:
    s.erase(
        std::remove_if(s.begin(), s.end(),
            [](const auto &stud){ return (stud.balls < 20); }
        ),
        s.end()
    );
    std::for_each(s.begin(), s.end(),
        [](auto &stud){ stud.balls = std::min(stud.balls, 100); }
    );
    */
}

int main()
{
    std::vector<Student> s;
    inputdata(s);
    print(s);
    fixdata(s);
    print(s);
    return 0;
}

【讨论】:

    【解决方案2】:

    该函数有一个错误,因为在 for 循环的下一次迭代中将子数组的元素向左移动后,您将处理另一个元素而不是所需的元素。该函数还应该在删除一些元素后返回实际元素的数量。

    该函数还可能产生内存泄漏,然后将数组的一个元素分配给数组的另一个元素。

    函数可以如下所示

    int fixdata( Student *s, int n )
    {
        int i = 0;
    
        for ( int j = 0; j < n; ++j )
        {
            if ( not ( s[j].balls < 20 ) )
            {
                if ( i != j ) 
                {
                    delete [] s[i].name;
                    s[i] = s[j];
                    s[j].name = nullptr;
                }
                if ( s[i].balls > 100 ) s[i].balls = 100;
                ++i;
            }
        }
    
        return i;
    }
    

    在 main 你可以写

    int m = fixdata(s, n);
    print(s, m);
    

    当不再需要数组时,你应该删除分配的内存。

    for ( int i = 0; i < n; i++ )
    {
        delete [] s[i].name;
    } 
    delete [] s;
    

    【讨论】:

      猜你喜欢
      • 2012-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-16
      • 1970-01-01
      • 2014-01-16
      • 2017-12-06
      相关资源
      最近更新 更多