Copying elements of an array using for loop vs struct pointers - c

If I have two arrays of the same size, let's say,
int pa1[100];
int pa2[100];
I know that if, at some point in the code, I want to copy the contents of pa2 in pa1,
pa1 = pa2;
is not the correct way to do it. Instead I could use perhaps a loop. However I was thinking that if I had two struct pointers (ps1, ps2) it is valid to write:
*ps1 = *ps2;
If that structure contained a 100 int array, and I made ps1 and ps2 point to pa1 and pa2 respectively, what is the difference between the previous instruction and a loop that copies every single element in the arrays?
for (int i = 0; i<100; i++) pa1[i] = pa2[i];
Does it have any performance difference? Why?
My first guess is that using the pointers is better than using a loop, but I am not sure. I tried to make a web search but had no success, maybe because I could not find the exact words that describe what I want to know.

Usually compilers uses standard C function memcpy in such cases. It is much faster then using a manually written loop.

Yes it works, as the program below demonstrate.
No you can't be really sure of the code the compiler will choose to do internally. But it is likely that the compiler will emit a very efficient code like calling memcopy (but no include necessary) or using optimized assembly.
But it can't be guaranteed. You will have to test or analyse generated assembly output.
On the readability part I believe copying structure is at least as easy to read than an explicit loop or call to memcopy. And it could be even better if the two arrays are acompanied by other variables related to the arrays that could also go to the structures.
#include <stdio.h>
int main() {
struct {
int t[10];
} s1, s2;
int i = 0;
for(i=0; i < 10 ; ++i){
s1.t[i] = i;
s2.t[i] = -1;
}
printf("s1 [%d %d ... %d %d] s2 [%d %d ... %d %d]\n",
s1.t[0], s1.t[1], s1.t[8], s1.t[9],
s2.t[0], s2.t[1], s2.t[8], s2.t[9]);
s2 = s1;
printf("s1 [%d %d ... %d %d] s2 [%d %d ... %d %d]\n",
s1.t[0], s1.t[1], s1.t[8], s1.t[9],
s2.t[0], s2.t[1], s2.t[8], s2.t[9]);
}

You mean this?
int pa1[100], pa2[100];
int *ps1 = pa1, *ps2 = pa2;
// Initialize the arrays
*ps1 = *ps2;
If it is, then all the last line is doing is:
pa1[0] = pa2[0];
nothing else.
If you need to copy all elements of an array to the other, you will need to iterate through them.
EDIT: On a second read, now I think you meant this:
struct a{
int v[100];
};
int pa1[100], pa2[100];
a *ps1, *ps2;
// Initialize the arrays
ps1 = (a*)pa1;
ps2 = (a*)pa2;
*ps1 = *ps2;
Pretty clever, although you won't find a definite answer for your question. That's implementation-specific, altough many implementations seem to use memcpy or something like it, witch may be barely a little faster than iterating the array. On a second note, your compiler will easily optimize a copy between two arrays using iteration, so the difference is probably negligible, and not worth the extra effort in writing the struct and the pointers in the first place.
So, the real question here is: why do you need such an optimization?

Related

Using struct field as loop counter?

Some background to the issue
if I have a struct like
typedef struct {
idx_type type;
union {
char *str;
int num;
} val
} cust_idx;
and I have loops like this
for (i = 0; i < some_get(x); i++) {
some_fun(z, NULL, i);
}
that I want to refactor to use the struct like some_fun(z, idx) where idx is one of my cust_idx structs, would it be best to keep i as the loop counter and update idx or change the for header to use idx.val.num instead of i?
For the purposes of this, assume idx_type is an enum for string and number types, and all other fields will have macros, but I'm only going to use the IDX_NUM macro here as I'm not worried about anything to do with idx.type.
To sum up my concerns:
Will it be readable? I don't want to leave behind a mess that someone will read and just shake their head...
Is it advised against?
Which of these is the best solution?
Struct field as loop counter
#define IDX_NUM(x) (x.val.num)
...
cust_idx j;
j.type = TYPE_num;
for (IDX_NUM(j) = 0; IDX_NUM(j) < some_get(x); IDX_NUM(j)++) {
some_fun(z, j);
}
This does the same as the original, but the using struct field/macro extends and complicates the for loop header in my opinion but it's still fairly understandable.
Modify struct with original counter
cust_idx j;
j.type = TYPE_num;
for (i = 0; i < some_get(x); i++) {
IDX_NUM(j) = i;
some_fun(z, j);
}
This results in the least changes from old code logically, but will end in by far the largest amount of code due to the add assignment lines.
Pointer to struct field
cust_idx j;
int *i = &(j.val.num);
j.type = TYPE_num;
for ((*i) = 0; (*i) < some_get(x); (*i)++) {
some_fun(z, j);
}
I'm not sure how good this would be in the long run, or if it's advised against.
As to readability, I would always prefer separate loop counters.
EDIT: The following in italic is not right in this specific case as C structs by default are passed as value copies over the stack, so passing j to some_fun() in the loop is ok. But I'll leave the caveat here, as it applies to many similar situations, where the struct or array is passed by a pointer value. (aka 'passed by reference').
That is especially true in code like you posted, where you call a function with the structure as an argument inside the loop.
If I don't know what some_fun() does, I can only hope that the struct's member that I use as a loop counter is not modified. And hope is not a strategy.
So, unless there are very hard reasons for doing otherwise, I'd always place readability first. Remember: If you write code that is at the limits of your own syntactic and semantic capabilities, you will have very little fun debugging such code, as debugging is an order of magnitude harder than writing (buggy) code. ;)
Addition: You could look at the disassemblies of all variants. The compiler might do a lot of optimizations here, especially if it can 'see' some_fun().

To know the size of an array in c

I am learning C language. I want to know the size of an array inside a function. This function receive a pointer pointing to the first element to the array. I don't want to send the size value like a function parameter.
My code is:
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
while( *(a + i) != NULL )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
My code doesn't show any number. How can I fix it?
Thanks.
Arrays in C are simply ways to allocate contiguous memory locations and are not "objects" as you might find in other languages. Therefore, when you allocate an array (e.g. int numbers[5];) you're specifying how much physical memory you want to reserve for your array.
However, that doesn't tell you how many valid entries you have in the (conceptual) list for which the physical array is being used at any specific point in time.
Therefore, you're required to keep the actual length of the "list" as a separate variable (e.g. size_t numbers_cnt = 0;).
I don't want to send the size value like a function parameter.
Since you don't want to do this, one alternative is to use a struct and build an array type yourself. For example:
struct int_array_t {
int *data;
size_t length;
};
This way, you could use it in a way similar to:
struct int_array_t array;
array.data = // malloc for array data here...
array.length = 0;
// ...
some_function_call(array); // send the "object", not multiple arguments
Now you don't have to write: some_other_function(data, length);, which is what you originally wanted to avoid.
To work with it, you could simply do something like this:
void display_array(struct int_array_t array)
{
size_t i;
printf("[");
for(i = 0; i < array.length; ++i)
printf("%d, ", array.data[i]);
printf("]\n");
}
I think this is a better and more reliable alternative than another suggestion of trying to fill the array with sentinel values (e.g. -1), which would be more difficult to work with in non-trivial programs (e.g. understand, maintain, debug, etc) and, AFAIK, is not considered good practice either.
For example, your current array is an array of shorts, which would mean that the proposed sentinel value of -1 can no longer be considered a valid entry within this array. You'd also need to zero out everything in the memory block, just in case some of those sentinels were already present in the allocated memory.
Lastly, as you use it, it still wouldn't tell you what the actual length of your array is. If you don't track this in a separate variable, then you'll have to calculate the length at runtime by looping over all the data in your array until you come across a sentinel value (e.g. -1), which is going to impact performance.
In other words, to find the length, you'd have to do something like:
size_t len = 0;
while(arr[len++] != -1); // this is O(N)
printf("Length is %u\n", len);
The strlen function already suffers from this performance problem, having a time-complexity of O(N), because it has to process the entire string until it finds the NULL char to return the length.
Relying on sentinel values is also unsafe and has produced countless bugs and security vulnerabilities in C and C++ programs, to the point where even Microsoft recommends banning their use as a way to help prevent more security holes.
I think there's no need to create this kind of problem. Compare the above, with simply writing:
// this is O(1), does not rely on sentinels, and makes a program safer
printf("Length is %u\n", array.length);
As you add/remove elements into array.data you can simply write array.length++ or array.length-- to keep track of the actual amount of valid entries. All of these are constant-time operations.
You should also keep the maximum size of the array (what you used in malloc) around so that you can make sure that array.length never goes beyond said limit. Otherwise you'd get a segfault.
One way, is to use a terminator that is unique from any value in the array. For example, you want to pass an array of ints. You know that you never use the value -1. So you can use that as your terminator:
#define TERM (-1)
void print(int *arr)
{
for (; *arr != TERM; ++arr)
printf("%d\n", *arr);
}
But this approach is usually not used, because the sentinel could be a valid number. So normally, you will have to pass the length.
You can't use sizeof inside of the function, because as soon as you pass the array, it decays into a pointer to the first element. Thus, sizeof arr will be the size of a pointer on your machine.
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
short j;
j = sizeof(*a) / sizeof(short);
while( i < j )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
Not sure if this will work tho give it a try (I don't have a pc at the moment)

Why does this C code work?

EDIT: Thank you very much for your responses. I understand this properly now!
I am trying to learn more on C pointers. Tinkering around, I am questioning the difference between two actions I am using.
This code seems to work at first glance, but I am not sure of what's the difference, and if any of these two approaches is wrong in some way.
I'd like to know what's the difference between the two pieces of code, when I should I pass the adress, and when a pointer to an array?
Is any of the pieces wrong? If so, what would be the proper way?
having a simple struct grid pretty much like struct grid { int val; } (for demonstration purposes)
First piece of code. Passing address of the pointer to the array.
void set (mygrid *grid, int foo){
grid->bar = foo; //should this be '*grid->bar?' But this seems to work properly.
}
void main(){
int i;
int* array;
int max = 24;
array = malloc(sizeof(grid) * max);
for(i = 0; i < max; i++){
set(&array[i], 0);
}
}
Second piece of code. I am not entirely sure why this works, but the compiler doesn't output any warning.
I am supposed to be passing the pointer to the start of the array like this?
void set(mygrid *grid, int foo){
int i; int max = 24; //so this example code compiles :P
for(i = 0; i < max; i++){
grid[i].bar = foo;
}
}
void main(){
int* array;
int max = 24;
array = malloc(sizeof(grid) * max);
set(array, 0); //Why not &array?
}
Passing an array decays into a pointer that points to the first member of the array, just like &array[0].
In your second example, array is just a pointer, and the return value from malloc is just the address of the start of the block of memory you get.
It doesn't have to be used for an array; it could be used for storage of an arbitrary sizeof(int) * max bytes of data. An array (in C) is really just a nice way of thinking about & working with a solid block of memory divided up into equal size portions.
Secondly, you should understand how my_array[i] works. All it does is take the address of where your block of array data starts (which is the actual value of my_array), and then look at what value is stored at a particular offset from there. Specifically, if my_array is of a (made up) type of WhatEver, then it will access the data from my_array + i*sizeof(WhatEver) to my_array + (i+1)*sizeof(WhatEver).
On a related note (since you're learning C), it's highly recommended to check that the return from malloc is not NULL before doing anything with it.
I'm no C guru but am also trying to improve my understanding so if this is incorrect, please leave a comment or edit my answer so I can learn from my mistakes :)
In your first piece of code
grid->bar is same as (*grid).bar
. and using name of an array refers to its base address. so writing array is equivalent &array[0]
&array[i] is equivalent to array+i
array[i] is equivalent to *(array +i)
In you second piece of code i dont understand why there is no error because in your function set you do not declare max and i dont see a global max variable too.
also in your second piece of code you use
set(array,0) because array is already an integer pointer(see the declaration int * array).As far as i understand the mygrid is not a struct but is an array of structs in the second example
In C, an array is pretty much the same as a pointer. For me this isn't so amazing, since it is one of the earlier programming languages I learned, but if you're coming from a high level language where an array is a different type of object, then it might come across as strange.

More efficient to use temporary variable or direct from array?

Is it more efficient to access an array each time I use a variable, or to create a temporary variable and set it to the array:
For example:
int A; int B; ...etc... int Z;
int *ints = [1000 ints in here];
for (int i = 0; i < 1000; i++) {
A = ints[i];
B = ints[i];
C = ints[i];
...etc...
Z = ints[i];
}
or
int A; int B; ...etc... int Z;
int *ints = [1000 ints in here];
for (int i = 0; i < 1000; i++) {
int temp = ints[i];
A = temp;
B = temp;
C = temp;
...etc...
Z = temp;
}
Yes, this is not something I want to do, but it is the easiest example I could think of.
So which for loop would be quicker at using the array?
It doesn't matter; the compiler will most likely produce the same code in both cases (unless you have disabled all optimizations). (The generated assembly code will likely resemble the second example - first, the array element will be loaded into a register, and then, the register will be used whenever the array element is needed.) Go with the style you find to be most readable and least prone to errors (which is probably the latter style, which avoids repeating the index).
(This assumes that you don't have any threads or volatile variables, so that the array element is guaranteed not to change in the course of a loop iteration.)
The compiler is smart enough to realize that these are equivalent and will produce the same code. You should therefore write it in the most understandable way for future people reading your code.
As Aasmund's answer states, there is likely no performance difference since the compiler will treat both in the same way. However, you might find assigning to a temporary variable gives improved code readability, and if in the future you want to use ints[i+1] throughout the loop you will only need to change one line rather than many. Never call a variable "temp" though, give it a useful name like currentInt.

Coding problem using a 2-d array of structs inside another struct in C

I am working with a 2-dimensional array of structs which is a part of another struct. It's not something I've done a lot with so I'm having a problem. This function ends up failing after getting to the "test" for-loop near the end. It prints out one line correctly before it seg faults.
The parts of my code which read data into a dummy 2-d array of structs works just fine, so it must be my assigning array to be part of another struct (the imageStruct).
Any help would be greatly appreciated!
/*the structure of each pixel*/
typedef struct
{
int R,G,B;
}pixelStruct;
/*data for each image*/
typedef struct
{
int height;
int width;
pixelStruct *arr; /*pointer to 2-d array of pixels*/
} imageStruct;
imageStruct ReadImage(char * filename)
{
FILE *image=fopen(filename,"r");
imageStruct thisImage;
/*get header data from image*/
/*make a 2-d array of of pixels*/
pixelStruct imageArr[thisImage.height][thisImage.width];
/*Read in the image. */
/*I know this works because I after storing the image data in the
imageArr array, I printed each element from the array to the
screen.*/
/*so now I want to take the array called imageArr and put it in the
imageStruct called thisImage*/
thisImage.arr = malloc(sizeof(imageArr));
//allocate enough space in struct for the image array.
*thisImage.arr = *imageArr; /*put imageArr into the thisImage imagestruct*/
//test to see if assignment worked: (this is where it fails)
for (i = 0; i < thisImage.height; i++)
{
for (j = 0; j < thisImage.width; j++)
{
printf("\n%d: R: %d G: %d B: %d\n", i ,thisImage.arr[i][j].R,
thisImage.arr[i][j].G, thisImage.arr[i][j].B);
}
}
return thisImage;
}
(In case you are wondering why I am using a dummy array in the first place, well it's because when I started writing this code, I couldn't figure out how to do what I am trying to do now.)
EDIT: One person suggested that I didn't initialize my 2-d array correctly in the typedef for the imageStruct. Can anyone help me correct this if it is indeed the problem?
You seem to be able to create variable-length-arrays, so you're on a C99 system, or on a system that supports it. But not all compilers support those. If you want to use those, you don't need the arr pointer declaration in your struct. Assuming no variable-length-arrays, let's look at the relevant parts of your code:
/*data for each image*/
typedef struct
{
int height;
int width;
pixelStruct *arr; /*pointer to 2-d array of pixels*/
} imageStruct;
arr is a pointer to pixelStruct, and not to a 2-d array of pixels. Sure, you can use arr to access such an array, but the comment is misleading, and it hints at a misunderstanding. If you really wish to declare such a variable, you would do something like:
pixelStruct (*arr)[2][3];
and arr would be a pointer to an "array 2 of array 3 of pixelStruct", which means that arr points to a 2-d array. This isn't really what you want. To be fair, this isn't what you declare, so all is good. But your comment suggests a misunderstanding of pointers in C, and that is manifested later in your code.
At this point, you will do well to read a good introduction to arrays and pointers in C, and a really nice one is C For Smarties: Arrays and Pointers by Chris Torek. In particular, please make sure you understand the first diagram on the page and everything in the definition of the function f there.
Since you want to be able to index arr in a natural way using "column" and "row" indices, I suggest you declare arr as a pointer to pointer. So your structure becomes:
/* data for each image */
typedef struct
{
int height;
int width;
pixelStruct **arr; /* Image data of height*width dimensions */
} imageStruct;
Then in your ReadImage function, you allocate memory you need:
int i;
thisImage.arr = malloc(thisImage.height * sizeof *thisImage.arr);
for (i=0; i < thisImage.height; ++i)
thisImage.arr[i] = malloc(thisImage.width * sizeof *thisImage.arr[i]);
Note that for clarity, I haven't done any error-checking on malloc. In practice, you should check if malloc returned NULL and take appropriate measures.
Assuming all the memory allocation succeeded, you can now read your image in thisImage.arr (just like you were doing for imageArr in your original function).
Once you're done with thisImage.arr, make sure to free it:
for (i=0; i < thisImage.height; ++i)
free(thisImage.arr[i]);
free(thisImage.arr);
In practice, you will want to wrap the allocation and deallocation parts above in their respective functions that allocate and free the arr object, and take care of error-checking.
I don't think sizeof imageArr works as you expect it to when you're using runtime-sized arrays. Which, btw, are a sort of "niche" C99 feature. You should add some printouts of crucial values, such as that sizeof to see if it does what you think.
Clearer would be to use explicit allocation of the array:
thisImage.arr = malloc(thisImage.width * thisImage.height * sizeof *thisImage.arr);
I also think that it's hard (if even possible) to implement a "true" 2D array like this. I would recommend just doing the address computation yourself, i.e. accessing a pixel like this:
unsigned int x = 3, y = 1; // Assume image is larger.
print("pixel at (%d,%d) is r=%d g=%d b=%d\n", x, y, thisImage.arr[y * thisImage.width + x]);
I don't see how the required dimension information can be associated with an array at run-time; I don't think that's possible.
height and width are undefined; you might want to initialise them first, as in
thisImage.height = 10; thisImage.width = 20;
also,
what is colorRGB?
*thisImage.arr = *imageArr; /*put imageArr into the thisImage imagestruct*
This won't work. You have to declare arr as colorRGB **, allocate it accordingly, etc.
it looks like you are trying to copy array by assignment.
You cannot use simple assignment operator to do that, you have to use some function to copy things, for example memcpy.
*thisImage.arr = *imageArr;
thisimage.arr[0] = imagearr[0];
The above statements are doing the same thing.
However this is not most likely what causes the memory corruption
since you are working with two dimensional arrays, do make sure you initialize them correctly.
Looking at the code, should not even compile: the array is declared as one-dimensional in your image structure but you refer to as two-dimensional?

Resources