Есть ли способы избежать «недопустимого преобразования int * в int» C ++? - PullRequest
0 голосов
/ 18 января 2020

Я получаю эту ошибку, когда пытаюсь скомпилировать свой код. У меня нет никаких * (указателей) и я не могу понять, почему я получаю это. Я работаю сейчас с template. Вы также можете проверить мой код:

#include <iostream>
#include <cstdlib>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;

template <class T>
class Set
{
public:
    T **p;
    int n;
    Set(){
    };
    Set(int n)
    {
        this->n = n;
        p = new T*[n];
    }
    ~Set()
    {
      if(p) delete []p; 
    }
    void setValues(T k,int l)
    {
        p = k;
        n = l;
    }
    void add(T k)
    {
        T p1;
        p1 = p;
        p = new T[n+1];
        p = p1;
        p[n+1] = k;
        n++;
    }
    void remove(T k)
    {
        T p1;
        int l =0;
        p1 = p;
        p = new T[n-1];
        for(int i=0;i<n;i++)
            if(p1[i]!=k) 
            {
                p[l] = p1[i];
                l++;
                n--;
            } 
    }
    void operator+(Set s)
    {
        for(int i=0;i<n;i++)
            p[i]+=s.p[i];
    }
    void operator-(Set s)
    {
        for(int i=0;i<n;i++)
            p[i]-=s.p[i];
    }
    void operator*(Set s)
    {
        for(int i=0;i<n;i++)
            p[i]*=s.p[i];
    }
    void show()
    {
        for(int i=0;i<n;i++)
            cout<<p[i]<<" | ";
    }
};
int main()
{
    Set<int> s1,s2;
    int arr[]={0,2,3,4,3,6};
    int n=6;
    float arr2[]={0.5,12.1,1.7,23.15};
    char arr3[]={'a','h','m','k','c','e'};
    s1.setValues(arr,n); // <------------- here is error;
    s1.show();

}

Я получаю сообщение об ошибке в этой строке s1.setValues(arr,n); Это setValues() метод:

void setValues(T k,int l)
{
    p = k;
    n = l;
}

Я пытался избежать ошибки, используя &, например: s1.setValues(arr,&n) и s1.setValues(arr,*n)

Также я пытался изменить ее в методе: void setValues(T k,int &l) и void setValues(T k,int *l) в классе: public: T **p; int *n; и public: T **p; int &n;

В моей первой версии я попытался использовать: s1.setValues(arr,6), где 6 - длина массива. Но я также получал ошибку;

Ответы [ 2 ]

1 голос
/ 18 января 2020

Редактировать: Я неправильно прочитал тип p, а также, очевидно, прочитал ошибку в обратном направлении.

Класс создан с T как int. Все массивы распадаются на указатели, поэтому arr имеет тип int*. Это означает, что вы не можете передать его в качестве первого аргумента setValues.

void setValues(T k, int l);

...

s1.setValues(arr, n); //arr is type int*, but k is of type int.

Боюсь, я не понимаю, что ваш код делает достаточно хорошо, чтобы предположить, как вы можете это исправить, но Вот почему компилятор выдает эту ошибку.

0 голосов
/ 18 января 2020

Предварительное замечание: поскольку вы не используете std :: set, я полагаю, что это упражнение, и вы не можете использовать std :: vector, который значительно облегчит управление p

Проблема (ы)

В этом коде есть некоторые противоречия, и некоторые другие ошибки, которые еще не появляются, потому что соответствующая функция-член шаблона не используется:

  • Член T** p определен как указатель на указатель на T
  • В конструкторе вы выделяете массив указателей на T, который действительно даст вам указатель на указатели на T.
  • Но в add() и remove() вы пытаетесь перераспределить p с помощью массива T, что даст вам T* вместо T**. Кроме того, вы явно хотите добавить или удалить значение, а не указатель.
  • Но в заданном значении неясно, хотите ли вы установить единственное значение (которое предлагает T k в подписи) или если вы хотите установить все значения из массива (длина которого аргумент int l предлагает). Учитывая, что имя функции имеет Values во множественном числе, я приму второй вариант.

Решение Шаг 1. Получите его для компиляции. Но на самом деле это не сработает

Вам нужно исправить:

T *p;  

и соответствующим образом адаптировать конструктор с помощью p = new T[n];

   auto p1 = p;

Затем вам нужно изменить определение функции на:

void setValues(T k[],int l)  // option 1 
void setValues(T *k,int l)   // or option 2 

Хорошая новость заключается в том, что код будет компилироваться

Плохая новость заключается в том, что не буду делать то, что вы хотите. Кроме того, код функции и некоторые другие проблемы вызовут UB (это означает, что может произойти много плохих вещей, включая повреждение памяти, cra sh, et c ...).

Решение Шаг 2: присвоение массивов, указателей и правила 3 ​​

Этот код не соответствует ожидаемому:

void setValues(T *k, int l)
{
    p = k;   // OUCH !!!!!! pointer copy and not copy of the array elements
    n = l;
}

В настоящее время вы делаете не копировать элементы массива, но вы заменяете указатель. Это приводит к следующим последствиям:

  • Сначала вы потеряете память, так как указатель на выделенную память потерян и никогда не будет освобожден.
  • секунду, вы сделаете этот указатель указателем на массив, который не был выделен с помощью new[], что может сильно повредить вам, когда вы позже delete[] этот указатель.
  • третий: массив, к которому ваши классовые точки могут быть удалены владельцем массива, и в этом случае вы будете использовать висячий указатель.

Таким образом, вам нужно адаптировать свой код следующим образом:

void setValues(T k[],int l) // change signature
{
    if (n!=l) {          // if the size is the same, we'll reuse p, if not:
        delete[] p;            // avoid the memory to leek 
        p= new T[l];           // start with a fresh memory 
        n = l;                 // define new length
    }
    for (int i=0; i<l; i++) 
        p[i]=k[i];              // copy array elements one by one 
}

Другая важная проблема - это правило 3 . Это не проблема с вашим текущим main(), но быстро станет: если вы работаете с указателями в конструкторе или деструкторе, вы должны определить конструктор копирования и оператор присваивания. Если вы этого не сделаете, вы рискуете закончить с мелкими копиями вашего набора (2 разных объекта, но с тем же указателем).

Решение Шаг 3: избавиться от оставшихся проблем

Во-первых, ваш конструктор по умолчанию оставляет p и n унифицированными. Это может быть случайное значение, которое может привести к тому, что деструктор попытается удалить то, что не было выделено. И то же самое для любой другой функции, которая предполагает, что вещи, которые приняли значения членов, были бы согласованными. Итак:

Set(){ 
    p=nullptr; 
    n=0; 
};

Тогда у вас есть аналогичные проблемы в add(), которые у вас были в setValues() с назначением указателя. Кроме того, вы go вышли за пределы, даже после переопределения: последний элемент массива p с элементом n+1 равен p[n], а не p [n + 1]. Я позволю вам в качестве упражнения, чтобы улучшить его.

Демо онлайн

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...