this seems to be a simple question, but i cannot get my head around it...
i want to set the elements of an array, based on some conditions, in the most elegant way.
this is my non-compiling pseudo code:
float*array=NULL;
switch(elements) {
case 1: array={1}; break;
case 2: array={7, 1}; break;
case 3: array={3, 2, -1}; break;
case 4: array={10, 20, 30, 40}; break;
default:break;
}
the size of the array is limited, so i could do something like 'float array[16];' as well, but the problem is obviously assignment in the case-statement.
i really don't want to do something like:
case 2: array[0]=1; array[1]=2;
my current (clumsy) implementation is:
#define ARRAYCOPY(dest, src) for(int i=0;i<sizeof(src)/sizeof(*src);i++)dest[i]=src[i]
// ...
case 2: do {float*vec={1, 2}; ARRAYCOPY(array, vec); } while(0); break;
i'm using the ARRAYCOPY define, since memcpy() doesn't seem to work. at least doing
float*vec={1, 2}; memcpy(array, vec, sizeof(vec)/sizeof(*vec);
did not fill any values into array.
i guess there must be a nicer solution?
There is the memcpy function in <string.h>, which is similar to what you implemented as ARRAYCOPY. It copies a block of memory of given size, in your case this size is number of elements in the array * size of an element in the array.
http://www.cplusplus.com/reference/clibrary/cstring/memcpy/
memcpy(destination_array, source_array, number_of_elements * size_of_element);
So, you'd have
// let's allocate exactly as much space as is needed
float* array = (float*)malloc(elements * sizeof(float));
// and now copy the elements we want
switch(elements) {
case 1: memcpy(array, (float[]){1}, 1 * sizeof(float)); break;
case 2: memcpy(array, (float[]){1, 2}, 2 * sizeof(float)); break;
case 3: memcpy(array, (float[]){1, 2, 3}, 3 * sizeof(float)); break;
case 4: memcpy(array, (float[]){10, 20, 30, 40}, 4 * sizeof(float)); break;
default:break;
}
How about:
float *global[] = {
NULL,
(float[]){1},
(float[]){1, 2},
(float[]){7, 8, 9},
};
/* ... make sure `elements` is in range */
float *array = global[elements];
EDIT
You're obviously free to continue using the switch:
switch(elements) {
case 1:
array = (float[]){1};
break;
}
Some options:
1) All of those arrays you may want to use declare on the stack somewhere else, and assign the pointer "array" to whichever one you will actually want. I think this is overly complex though to have these rather pointless arrays floating around.
2) Why doesn't memcpy work? Just remember it thinks in terms of bytes not array elements, so memcpy(target, source, sizeof(source)) should work fine provided target is bigger. I would wrap with if(sizeof(target) > sizeof(source)) { handle error } like this:
case 3:
float temp[] = {1.0,2.0,3.0};
memcpy(array, temp, sizeof(temp));
Make sure you allocate memory (stack or heap) and keep track of the semantic size of array.
Related
This could be a very basic question but it really bugs me a lot. What I am trying to do is basically to copy elements in an old vector to a new vector using C.
The copy is based on an index vector where each element in this vector represents the index of the element in the old vector. The index vector is not sorted.
For example,
an old vector A = [3.4, 2.6, 1.1].
a index vector B = [1, 1, 3, 3, 2, 1, 2].
After copy, I would expect the new vector to be C = [3.4, 3.4, 1.1, 1.1, 2.6, 3.4, 2.6].
The most brutal solution I can think of is to run a loop through B and copy the corresponding element in A to C. But when the vector is too large, the cost is not bearable.
My question is, is there a faster/smarter way to do copy in C on this occasion?
Originally the code is written in Julia and I had no problem with that. In Julia, I simply use C = A[B] and it is fast. Anyone knows how they do it?
Add the C pseudo code:
float *A = []; # old array
int *B = []; # index array
float *C;
for(i=0;i<length(B);i++)
{
*(C+i) = *(A+*(B+i));
}
Assumption: length(B) isn't actually a function but you didn't post what it is. If it is a function, capture it in a local variable outside the for loop and read it once; else you have a Schlemiel the Painter's Algorithm.
I think the best we can do is Duff's Device aka loop unrolling. I also made some trivial optimizations the compiler can normally make, but I recall the compiler's loop unrolling isn't quite as good as Duff's device. My knowledge could be out of date and the compiler's optimizer could have caught up.
Probing may be required to determine the optimal unroll number. 8 is traditional but your code inside the loop body is larger than normal.
This code is destructive to the pointers A and B. Save them if you want them again.
float *A = []; # old array
int *B = []; # index array
float *C;
int ln = length(B);
int n = (ln + 7) % 8;
switch (n % 8) {
case 0: do { *C++ = A[*B++];
case 7: *C++ = A[*B++];
case 6: *C++ = A[*B++];
case 5: *C++ = A[*B++];
case 4: *C++ = A[*B++];
case 3: *C++ = A[*B++];
case 2: *C++ = A[*B++];
case 1: *C++ = A[*B++];
} while (--n > 0);
}
With this much scope I can do no better, but with a larger scope a better choice might exist involving redesigning your data structures.
Say I initialize an array of 5 integer elements like this:
int *Q = malloc(sizeof(int) * 5);
for (int i = 0; i < 5; i++) {
Q[i] = i;
}
The array looks like: {0, 1, 2, 3, 4}.
Now if I shift everything along by 1 position:
Q++;
The array looks like: {1, 2, 3, 4, #}, where # is some garbage value.
Is there a way to free the final element so it's not stored in the array?
I tried this:
free(Q[4]);
But I know this won't work because free() can only operate of the whole chunk of memory allocated for Q.
Is there a better way to shift everything along? The resulting array should look like: {1, 2, 3, 4}.
Would it be a good idea to realloc() Q after every shift?
realloc() can change the size of an allocated chunk of memory, which will do the job for you. Note that this cannot be used to "free" arbitrary elements of an array, but only one(s) on the end.
How good an idea it is to do this depends on a number of factors, none of which you have provided.
When you do Q++ the array has not changed, it still contains the five values 0,1,2,3,4 it is just that Q is pointing to the second element in the array.
If you want to change the size of allocated memory then do as Scott said and realloc the block - but it is a costly way of handling heap memory.
If you just want to keep track of the number of elements in the array let Q remain pointing on the first element and have a size variable indicating how many integers there are.
Alternatively use another data structure to hold your integers e.g. a linked list of integers, then you can add and remove integers easier.
Taliking about last elements of array you can surely use realloc
BTW take note that when you say
The array looks like: {1, 2, 3, 4, #}, where # is some garbage value.
You are wrong and you are invoking undefined behavior as well explained by this SO answer.
So the loop that left shift value have not to do Q[4] = Q[5];
To shift around elements inside an array one can use memmove().
#include <stdio.h>
#include <string.h>
int main(void)
{
int d_init[] = {0, 1, 2, 3, 4};
size_t s = sizeof d_init/sizeof *d_init;
int d[s];
/* Fill d */
memcpy(d, d_init, s * sizeof *d);
for (size_t i = 0; i < s; ++i)
printf("%d ", d[i]);
puts("\n");
/* shift one to the left */
memmove(d, d + 1, (s - 1) * sizeof *d);
for (size_t i = 0; i < s; ++i)
printf("%d ", d[i]);
puts("\n");
/* shift two to the right */
memmove(d + 2, d, (s - 2) * sizeof *d);
for (size_t i = 0; i < s; ++i)
printf("%d ", d[i]);
puts("\n");
}
The snippet above would print:
0 1 2 3 4
1 2 3 4 4
1 2 1 2 3
If you're doing a Q++ you've not shifted the elements of the array, your array is simply pointing to the second element (index 1). Thus, Q[4] is reading something that doesn't belong to the array: C is permissive enough to let you do that (in most cases), but it is a mistake.
To shift elements you should either do
for (int i=0; i<4; i++)
Q[i] = Q[i+1];
or (smarter)
memmove(Q, Q+1, 4*sizeof(int));
but indeed, to have an array of size 4 you'll have to realloc.
BUT if you need to do that, maybe an array is not the data structure you should use: a linked list seems to be a better choice.
We know that a Duff's device makes use of interlacing the structures of a fallthrough switch and a loop like:
send(to, from, count)
register short *to, *from;
register count;
{
register n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
}
Now, in Swif 2.1, switch-case control flows do not implicitly have fallthrough as we read in Swift docs:
No Implicit Fallthrough
In contrast with switch statements in C and Objective-C, switch
statements in Swift do not fall through the bottom of each case and
into the next one by default. Instead, the entire switch statement
finishes its execution as soon as the first matching switch case is
completed, without requiring an explicit break statement. This makes
the switch statement safer and easier to use than in C, and avoids
executing more than one switch case by mistake.
Now, given that there's a fallthrough clause to have explicitly a fallthrough side effect in Swift:
Fallthrough
Switch statements in Swift do not fall through the bottom of each case
and into the next one. Instead, the entire switch statement completes
its execution as soon as the first matching case is completed. By
contrast, C requires you to insert an explicit break statement at the
end of every switch case to prevent fallthrough. Avoiding default
fallthrough means that Swift switch statements are much more concise
and predictable than their counterparts in C, and thus they avoid
executing multiple switch cases by mistake.
that is pretty much like:
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// prints "The number 5 is a prime number, and also an integer."
considering that as Wikipedia reminds to us, the devices comes out from the issue
A straightforward code to copy items from an array to a memory-mapped output register might look like this:
do { /* count > 0 assumed */
*to = *from++; /* "to" pointer is NOT incremented, see explanation below */
} while(--count > 0);
Which would be the exact implementation of a Duff's device in Swift?
This is just a language & coding question, it is not intended to be applied in real Swift applications.
Duffs device is about more than optimisation. If you look at https://research.swtch.com/duff it is a discussion of implementing co-routines using this mechanism (see paragraph 8 for a comment from Mr. Duff).
If you try to write a portable co-routine package without this ability. You will end up in assembly or re-writing jmpbuf entries [ neither is portable ].
Modern languages like go and swift have more restrictive memory models than C, so this sort of mechanism (I imagine) would cause all sorts of tracking problems. Even the lambda-like block structure in clang,gcc end up intertwined with thread local storage, and can cause all sorts of havoc unless you stick to trivial applications.
You express your intent in the highest level code possible, and trust the Swift compiler to optimize it for you, instead of trying to optimize it yourself. Swift is a high level language. You don't do low level loop unrolling in a high level language.
And in Swift, especially, you don't need to worry about copying arrays (the original application of Duff's Device) because Swift pretends to copy an array whenever you assign it, using "copy on write." This means that it will use the same array for two variables as long as you are just reading from them, but as soon as you modify one of them, it will create a duplicate in the background.
For example, from https://developer.apple.com/documentation/swift/array
Modifying Copies of Arrays
Each array has an independent value that includes the values of all
of its elements. For simple types such as integers and other structures,
this means that when you change a value in one array, the value of that
element does not change in any copies of the array. For example:
var numbers = [1, 2, 3, 4, 5]
var numbersCopy = numbers
numbers[0] = 100
print(numbers)
// Prints "[100, 2, 3, 4, 5]"
print(numbersCopy)
// Prints "[1, 2, 3, 4, 5]"
The maximum elements position in an array 'array[n]' has to be found, hence using the following code
int i, maximum; int location = 1;
//the array value and n value will be scanned in
maximum = array[0];
for( i=0; i<n; i++ ) {
if(array[i] > maximum){
maximum = array[i];
location = i+1;
}
}
return location;
this returns the output for example array below
(int[]) {1, 2, 3}, 3 -> location 3
(int[]) {5, 15, 4, 7}, 4 -> location 2
hence in the case of above array the code works well. when an array contains the two or more instance of the greater number, the code fails.
(int[]) {15, 15, 5, 7}, 4 -> location 1 (checks 1st location and stays)
(int[]) {45, 23, 55, 45}, 4 -> location 2 (checks 1st location and stays)
to solve the maximum instance location problem, how can the next instance location be found?
Firstly, in the examples you have given
(int[]) {1, 2, 3}, 3 -> location 3
(int[]) {5, 15, 4, 7}, 4 -> location 2
3 in the first example is in the same position as 4 in the second example, so they should technically have the same location. I'm not sure which code you've used to determine these locations, but it's inconsistent.
Your third and fourth examples are similarly inconsistent. This inconsistency puts doubt on your requirements, despite the clarity of the rest of the question.
A full minimal testcase is usually required for StackOverflow. The requirements are:
Your code must be minimal. Whatever the problem is, it should be easy for us to spot. As a guideline, if your code is greater than 50 lines you should try to trim any unnecessary logic away, filling in the gaps with static values where necessary.
If your problem is an error message, your code must produce the same error message.
If your problem is logical, your code must compile and run, producing the errant behaviour without us having to fill in the blanks or correct any errors, preferably without us even having to enter any input.
Your code doesn't compile, but it's easy enough to wrap it into a function and add a main entry point so it does. It would be best if, in the future, you were to take these steps in producing your minimal testcase.
size_t get_first_maximum_index(int *array, size_t array_size) {
int i, maximum; int location = 1;
//the array value and n value will be scanned in
maximum = array[0];
for( i=0; i<n; i++ ) {
if(array[i] > maximum){
maximum = array[i];
location = i+1;
}
}
return location;
}
I have taken the liberty to add the required interface to your code, but I've left your code unchanged. All you have to do is connect the logic to the interface:
Use array_size instead of n.
return actual array indexes, rather than array indexes + 1.
Suggestion: Use size_t instead of int for array indexes (i and location), since array indexes should never be negative.
Once you've done that, you should be able to use this function to gather the initial maximum index like so: size_t index = get_first_maximum_index(array, array_size);
... as for each instance of the same value, you'll need a different function, which I suggest be named get_next_maximum_index.
size_t get_next_maximum_index(int *array, size_t array_size, int current_maximum) {
/* XXX:
* Find the next value within array that contains current_maximum and return it,
* ... or array_size if none found
*/
}
I feel confident that, providing you were the one who wrote the code you posted in the OP, you should be able to finish that function off yourself. It would follow that an example of finding the first and subsequent indexes for maximum values would look something like this:
#include <stdio.h>
#include "maximum_int_search.h"
int main(void) {
int array[] = { 15, 15, 5, 7 };
size_t array_size = sizeof array / sizeof *array;
size_t index = get_first_maximum_index(array, array_size);
do {
printf("Maximum value at array[%zu]: %d\n", index, array[index]);
index = get_next_maximum_index(array + index + 1, array_size - index - 1);
} while (index != array_size);
}
If you have any problems with these tasks, feel free to ask further questions in the comments.
Hope my question is clear and relavent, new to Pointers... - Can I copy a whole portion of an array at once, by refering to the pointer to the location of the first slot in the array I want to begin copying from?
For example -
Given an array : A [ 1,2,3,4,5,7,8,3,2,5,1,0,9]
- I want to copy only the part of the array from the n'th slot on, into the beginning of the array B [0 0 0 ..... ] (B is of the same length of A).
Can I do it at once, using pointers instead of a loop? Something like - switching the pointer to the 1'st slot in B with the pointer to the n'th slot of A, and the n'th slot in B with the last one in A?
Thanks a lot on advance!
That's what memcpy is for.
memcpy(B, A + n, (N - n) * sizeof(A[0]));
where N is the number of elements in A. If A is really an array (not just a pointer to one), then N can be computed as sizeof(A) / sizeof(A[0]), so the call simplifies to
memcpy(B, A + n, sizeof(A) - n * sizeof(A[0]));
memcpy lives in <string.h>; its first argument is the destination of the copy, its second the source.
(I'm sorry, I don't really follow what kind of pointer trick you have in mind, so I can't comment on that.)
I think I understand what you're asking. You can use pointers to set up your second array, but here is the problem with doing it that way:
int [] primary = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int * secondary = primary + 5;
At this point, primary is { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }, and secondary is { 6, 7, 8, 9, 0 }, but the problem is they both point to the same array in memory. So instead of having two independent copies, if you edit any of the elements of 'secondary', they are edited in 'primary' also.
secondary[2] = 10;
for(int i = 0; i < 10; ++i)
cout << primary[i] << ' ';
This portion of code would now yield:
1 2 3 4 5 6 7 10 9 0
The correct way to do it would to either be setting up the new array, and looping through copying over the values, or using memcpy().
Edit:
//Rotate an array such that the index value is moved to the front of the array
null rotateArray( &int original[], int size, int index)
{
int * secondary = new int[size]; //dynamically allocated array
for(int i = 0; i < size; ++i)
{
secondary[i] = original[(i+index)%size];
}
original = secondary; //Move the original array's pointer to the new memory location
}
Some notes:
secondary[i] = original[(i+index)%size];
this is how I rotated the array. Say you had an original array of size 5, and you wanted the fourth element to be the new start (remember, elements are numbered 0-(size-1)):
i = 0;
secondary[0] = original[(0 + 3)%5]// = original[3]
i = 1;
secondary[1] = original[(1 + 3)%5]// = original[4]
i = 2;
secondary[2] = original[(2 + 3)%5]// = original[0]
...
The last part of the code:
original = secondary;
is a little bit questionable, as I don't remember whether or not c++ will try and clean up the used memory once the function is exited. A safer and 100% sure way to do it would be to loop through and copy the secondary array's elements into the original array:
for(int i = 0; i < size; ++i)
original[i] = secondary[i];