std :: массив эквивалент в C - PullRequest
       12

std :: массив эквивалент в C

0 голосов
/ 01 сентября 2018

Я новичок в C и C ++, и я читал, что по крайней мере в C ++ предпочтительно использовать std :: array или std :: vector при использовании векторов и массивов, особенно при передаче их в функцию.

В своем исследовании я обнаружил следующее, что имеет смысл. Я полагаю, что использование std :: vector решит проблему индексации вне области видимости переменной.

void foo(int arr[10]) { arr[9] = 0; }

void bar() {
    int data[] = {1, 2};
    foo(data);
}

приведенный выше код неверен, но компилятор считает, что все в порядке и не выдает предупреждений о переполнении буфера.

Вместо этого используйте std :: array или std :: vector, которые имеют постоянное значение семантика и отсутствие какого-либо «специального» поведения, которое приводит к ошибкам, таким как выше.

(ответ от bames53, спасибо, кстати!)

То, что я хочу закодировать, это

float foo(int X, int Y, int l){
    // X and Y are arrays of length l
    float z[l];
    for (int i = 0; i < l; i ++){
        z[i] = X[i]+Y[i];
    }
    return z;
}

int bar(){
    int l = 100;
    int X[l];
    int Y[l];
    float z[l];
    z = foo(X,Y,l);
    return 0;
}

Я хочу, чтобы это было закодировано в C, поэтому мой вопрос: есть ли std :: vector конструкция для C? Я ничего не мог найти по этому поводу.

Заранее спасибо, также прошу прощения за мое кодирование (я зеленый, как трава в C и C ++)

Ответы [ 3 ]

0 голосов
/ 01 сентября 2018

Ближайшим эквивалентом std::array в c, вероятно, является определение макроса препроцессора, например

#define ARRAY(type,name,length) \
     type name[(length)]
0 голосов
/ 01 сентября 2018

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

C ++ и C разделяют огромную часть таким образом, что код C может (без большого количества модификаций) быть скомпилирован как C ++. Однако, если вы научитесь осваивать C ++, вы поймете, что происходит много странных вещей из-за того, как работает C.

Возвращаясь к делу: C ++ содержит стандартную библиотеку с контейнерами std::vector. Эти контейнеры используют несколько конструкций C ++, которые недоступны в C:

  • RAII (тот факт, что Destructor запускается, когда экземпляр выходит из области видимости) предотвратит утечку памяти из выделенной памяти
  • Шаблоны позволят типу безопасности не смешивать двойники, числа с плавающей запятой, классы ...
  • Перегрузка оператора допускает разные подписи для одной и той же функции (например, стирание)
  • Функции-члены

Ничего из этого не существует в C, поэтому для того, чтобы иметь подобную структуру, для получения структуры данных, которая ведет себя почти одинаково, требуется несколько адаптаций.

По моему опыту, большинство C-проектов имеют свои собственные общие версии структур данных, часто основанные на void*. Часто это будет выглядеть примерно так:

 struct Vector
 {
      void *data;
      long  size;
      long  capacity;
 };

 Vector *CreateVector()
 {
      Vector *v = (Vector *)(malloc(sizeof(Vector)));
      memset(v, 0, sizeof(Vector));
      return v;
 }

 void DestroyVector(Vector *v)
 {
      if (v->data)
      {
          for (long i = 0; i < v->size; ++i)
              free(data[i]);
          free(v->data);
      }
      free(v);
 }

 // ...

Кроме того, вы можете смешивать C и C ++.

 struct Vector
 {
      void *cppVector;
 };

 #ifdef __cplusplus
 extern "C" {
 #endif

 Vector CreateVector()
 void DestroyVector(Vector v)

 #ifdef __cplusplus
 }
 #endif

vectorimplementation.cpp

 #include "vector.h"

 struct CDataFree
 {
       void operator(void *ptr) { if (ptr) free(ptr); }
 };
 using CData = std::unique_ptr<void*, CDataFree>;

 Vector CreateVector()
 {
      Vector v;
      v.cppVector = static_cast<void*>(std::make_unique<std::vector<CData>>().release());
      return v;
 }

 void DestroyVector(Vector v)
 {
      auto cppV = static_cast<std::vector<CData>>(v.cppVector);
      auto freeAsUniquePtr = std::unique_ptr<std::vector<CData>>(cppV);
 }

 // ...
0 голосов
/ 01 сентября 2018

Стандарт C не имеет ничего общего с std::vector или другими контейнерными структурами. Все, что вы получаете, это встроенные массивы и malloc.

Полагаю, использование std :: vector решит проблему индексации вне области действия переменной.

Вы можете так думать, но вы ошибаетесь: индексирование за пределами std::vector так же плохо, как и со встроенным массивом. operator[] из std::vector также не выполняет проверку границ (или, по крайней мере, это не гарантируется). Если вы хотите, чтобы ваши операции с индексами проверялись, вам нужно использовать arr.at(i) вместо arr[i].

Также обратите внимание, что код типа

float z[l];
...
return z;

неверно, потому что в C нет значений массива (или C ++, если на то пошло). Когда вы пытаетесь получить значение массива, вы фактически получаете указатель на его первый элемент. Но этот первый элемент (и все другие элементы, и весь массив) уничтожается, когда функция возвращается, так что это классическая ошибка использования после освобождения: вызывающая сторона получает висячий указатель на объект, который больше не существует.

Обычное решение C состоит в том, чтобы вызывающая сторона имела дело с распределением памяти и передавала выходной параметр, в который функция просто записывает:

void foo(float *z, const int *X, const int *Y, int l){
    // X and Y are arrays of length l
    for (int i = 0; i < l; i ++){
        z[i] = X[i]+Y[i];
    }
}

Тем не менее, есть некоторые библиотеки, которые предоставляют динамические структуры данных для C, но они обязательно должны выглядеть и чувствовать себя очень отличающимися от C ++ и std::vector (например, я знаю о GLib ).

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