Заменить массив другим массивом в C - PullRequest
0 голосов
/ 09 ноября 2011

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

typedef struct _test {
   float value;
} test;

Достаточно просто struct, поэтому я попробовал это:

test struct1[10];
test struct2[20];
struct1 = struct2;

Я не думал, что это сработает, и даже не скомпилировалось. Но это меня очень интересует. Можно ли взять массив из 10 и увеличить размер до 20 при копировании данных?

Objective-C

На самом деле я делаю это с Objective-C, поэтому я хотел бы услышать также и от людей из Objective-C. Я хочу посмотреть, возможно ли изменить размер struct1 в этом файле.

@interface Object : NSObject {
    test struct1;
}

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

Ответы [ 7 ]

3 голосов
/ 09 ноября 2011

Еще одна вещь, которая не совсем относится к вашему вопросу, но тем не менее интересна, заключается в том, что, хотя массивы не могут быть назначены, структурам, содержащим массивы , можно присвоить :

struct test
{
    float someArray[100];
};


struct test s1 = { /* initialise with some data*/ };
struct test s2 = { /* initialise with some other data */ };

s1 = s2; /* s1's array now contains contents of s2's array */

Это также позволяет возвращать массивы данных фиксированной длины из функций (поскольку возврат простых массивов недопустим):

struct test FunctionThatGenerates100Floats(void)
{
    struct test result;
    for (int i = 0; i < 100; i++)
        result.someArray[i] = randomfloat();

    return result;
}
2 голосов
/ 09 ноября 2011

Как уже говорили другие, выделенные массивы статичны и не могут быть изменены. Вы должны использовать указатели (выделение массива с malloc или calloc), чтобы иметь массив с изменяемым размером, а затем вы можете использовать realloc. Вы должны использовать free, чтобы избавиться от него (иначе вы потеряете память). В C99 размер вашего массива может быть вычислен во время выполнения, когда он выделен (в C89 его размер должен был быть вычислен во время компиляции), но его нельзя изменить после выделения. В C ++ вы должны использовать std::vector. Я подозреваю, что Objective-C имеет что-то вроде вектора C ++.

Но если вы хотите скопировать данные между одним массивом и другим в C, используйте memcpy:

/* void *memcpy(void *dest, const void *src, size_t n)
   note that the arrays must not overlap; use memmove if they do */
memcpy(&struct1, &struct2, sizeof(struct1));

Разумеется, это скопирует только первые десять элементов, поскольку struct1 имеет длину всего десять элементов. Вы можете скопировать последние десять (например), изменив &struct2 на struct2+10 или &(struct2[10]). В C, конечно, вы не запускаете конец массива: memcpy не проверяет.

Вы также можете использовать цикл for, но memcpy часто будет быстрее (и никогда не должен быть медленнее). Это связано с тем, что компилятор может использовать все известные ему приемы (например, он может знать, как копировать данные по 16 байт за раз, даже если каждый элемент имеет ширину всего 1 байт)

2 голосов
/ 09 ноября 2011

Вы не можете сделать это в C со статическими массивами, но вы можете сделать это с динамически размещенными массивами.Например,

float *struct1, *struct2, *struct3;
if(!(struct1 = malloc(10 * sizeof(float))) { 
  // there was an error, handle it here
}
if(!(struct2 = realloc(struct1, 20 * sizeof(float))) {
  // there was an error, handle it here
  // struct1 will still be valid
}
if(!(struct3 = reallocf(struct2, 40 * sizeof(float))) {
  // there was an error, handle it here
  // struct2 has been free'd
}
1 голос
/ 09 ноября 2011

Если вы используете Objective C, вы знаете, что вы можете просто использовать NSMutableArray, который автоматически выполняет трюк realloc, чтобы перераспределить себя для хранения любого количества объектов, которые вы в него поместили, до предела вашей памяти.

Но вы пытаетесь сделать это с помощью struct? Что бы это вообще значило? Предположим, вы увеличиваете объем памяти, доступной для struct1 в Object. Это все еще структура с одним членом, и больше ничего не делает.

Может ли идея сделать Object способным содержать расширенную структуру?

typedef struct _test2 {
    float value;
    NSObject *reference;
} test2;

Но тогда вы все равно не можете получить доступ к reference в обычном режиме, потому что это не известная часть Object.

Object *object2;
...
NSLog(@"%@", object2.struct1.reference); // does not compile

Если бы вы знали, что у вас есть один из ваших измененных объектов, вы могли бы сделать

Object *object2;
...
NSLog(@"%@", ((test2)(object2.struct1)).reference);

А также вы все еще можете предположительно передать object2 всему, что ожидает Объект. Он может работать только в том случае, если struct1 является последним членом Object, и также не связывайтесь с подклассами Object.

Тогда могут сработать различные трюки с realloc, но я не думаю, что realloc, в частности, потому что это предназначено для использования на объектах, которые выделены с помощью malloc, и подробности того, какая функция C используется для распределения объектов в не выставлено в Objective C, поэтому вы не должны предполагать, что это malloc. Если вы переопределите alloc, вы сможете убедиться, что используется malloc.

Также вы должны следить за тем, что в Objective C обычно существует более одного указателя на существующий объект. realloc может переместить объект, который не будет семантически правильным, если вы не исправите все указатели.

1 голос
/ 09 ноября 2011

Ясно, что если вы объявите массив с фиксированным размером, test struct1[10], тогда его размер не может быть изменен. Что вам нужно сделать, это объявить его как указатель:

test *struct1;

Затем вы должны использовать malloc для выделения массива и можете использовать realloc для изменения его размера при сохранении содержимого исходного массива.

struct1 = malloc(10*sizeof(*struct1));
//initialize struct1 ...
test *struct2 = realloc(struct1, 20*sizeof(*struct1));
1 голос
/ 09 ноября 2011

В массивах C это константы, вы вообще не можете изменить их значение (то есть их адрес) и не можете изменить их размер.

1 голос
/ 09 ноября 2011

В C я считаю, что это хорошее место для использования функции realloc.Однако он будет работать только с динамически размещаемыми массивами.Нет способа изменить память, выделенную для struct1 объявлением test struct1[10];.

...