Justin
Justin

Reputation: 2142

Replace array with another array in C

Out of pure curiosity, I started playing with array's in ways that I have never used before. I tried making a data structure array, and set it equal to another:

typedef struct _test {
   float value;
} test;

Simple enough struct, so I tried this:

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

I didn't think this would work, and it didn't even compile. But, this interests me a lot. Is it possible to take an array of 10 and increase the size to 20, while copying the data?

Objective-C

I am actually doing this with Objective-C, so I'd like to hear from the Objective-C people as well. I want to see if it is possible to change the size of struct1 in this file.

@interface Object : NSObject {
    test struct1;
}

Remember: This is only out of curiosity, so everything is open to discussion.

Upvotes: 0

Views: 12061

Answers (7)

morningstar
morningstar

Reputation: 9122

If you're using Objective C, you know you can just use NSMutableArray, which automatically does the realloc trick to reallocate itself to store however many objects you put in it, up the limit of your memory.

But you're trying to do this with struct? What would that even mean? Suppose you increase the amount of memory available to struct1 in Object. It's still a struct with one member, and doesn't do anything more.

Is the idea to make Object be able to contain an expanded struct?

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

But then you still can't access reference normally, because it's not a known part of Object.

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

If you knew you had one of your modified objects, you could do

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

And also you could still presumably pass object2 to anything that expects an Object. It only has any chance of working if struct1 is the last member of Object, and don't mess with subclassing Object either.

Some variety of realloc trick might then work, but I don't think realloc in particular, because that's intended to be used on objects that are allocated with malloc, and the details of what C function is used to allocate objects in not exposed in Objective C, so you shouldn't assume it's malloc. If you override alloc then you might be able to make sure malloc is used.

Also you have to watch out for the fact that it's common in Objective C for more than one pointer to an object to exist. realloc might move an object, which won't be semantically correct unless you correct all the pointers.

Upvotes: 1

Anthony Blake
Anthony Blake

Reputation: 5348

You can't do this in C with static arrays, but you can do it with dynamically allocated arrays. E.g.,

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
}

Upvotes: 2

derobert
derobert

Reputation: 51137

As others have said, arrays allocated like that are static, and can not be resized. You have to use pointers (allocating the array with malloc or calloc) to have a resizable array, and then you can use realloc. You must use free to get rid of it (else you'll leak memory). In C99, your array size can be calculated at runtime when its allocated (in C89, its size had to be calculated at compile time), but can't be changed after allocation. In C++, you should use std::vector. I suspect Objective-C has something like C++'s vector.

But if you want to copy data between one array and another in C, use 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));

That'll only copy the first ten elements, of course, since struct1 is only ten elements long. You could copy the last ten (for example) by changing &struct2 to struct2+10 or &(struct2[10]). In C, of course, not running off the end of the array is your responsibility: memcpy does not check.

You can also you the obvious for loop, but memcpy will often be faster (and should never be slower). This is because the compiler can take advantage of every trick it knows (e.g., it may know how to copy your data 16 bytes at a time, even if each element is only 1 byte wide)

Upvotes: 2

dreamlax
dreamlax

Reputation: 95325

Something else that is not exactly pertinent to your question but is interesting nonetheless, is that although arrays cannot be assigned to, structs containing arrays can be assigned to:

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 */

This also makes it possible to return fixed-length arrays of data from functions (since returning plain arrays is not allowed):

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

    return result;
}

Upvotes: 4

David Heffernan
David Heffernan

Reputation: 612844

Clearly if you declare your array with a fixed size, test struct1[10] then it cannot be resized. What you need to do is to declare it as a pointer:

test *struct1;

Then you must use malloc to allocate the array and can use realloc to resize it whilst preserving the contents of the original array.

struct1 = malloc(10*sizeof(*struct1));
//initialize struct1 ...
test *struct2 = realloc(struct1, 20*sizeof(*struct1));

Upvotes: 1

zmbq
zmbq

Reputation: 39013

In C arrays are constants, you can't change their value (that is, their address) at all, and you can't resize them.

Upvotes: 1

Ted Hopp
Ted Hopp

Reputation: 234795

In C, I believe that's a good place to use the realloc function. However, it will only work with dynamically allocated arrays. There's no way to change the memory allocated to struct1 by the declaration test struct1[10];.

Upvotes: 1

Related Questions