I have a structure that I pass to a function as constant pointer, my question is the following: There is a difference between those two implementations of function updatedFields:
typedef struct
{
int spec[100];
int spec1[200];
int spec2[200];
int spec3[500];
int spec4[100];
int spec5[700];
float value[100];
char desc[1000]:
}t_product;
void updateFields_1(t_product const* context)
{
int i,buffer[1500];
int * pt_int;
pt_int = (int*)context->spec1;
for(i = 0; i < 200; i++)
{
buffer[i] = pt_int[i];
}
pt_int = (int*)context->spec3;
for(i = 0; i < 500; i++)
{
buffer[i] = pt_int[i];
}
...
}
void updateFields_2(t_product const* context)
{
int i,buffer[1500];
for(i = 0; i < 200; i++)
{
buffer[i] = context->spec1[i];
}
for(i = 0; i < 500; i++)
{
buffer[i] = context->spec3[i];
}
...
}
int main(void)
{
t_product prod;
/* Initialisation of the structure */
...
updateField(&prod);
}
I mean, there is any advantages to use pointer to member of a struct (pointer to the arrays) instead of accessing directly to the member of struture.
It's probably a dumb question but I don't know if the access of a struct member "costs" more operations.
It won't ever cost more in your case. Even without optimization. Actually your pt_int example is likely to be slightly worse if you don't enable optimizations.
This is because context->spec3[i] isn't dereferencing more pointers than pt_int[i]. pt_int[i] is just a pointer plus an offset, so the access can be written as #(ptr_int + 4*i). In context->spec3[i], it could look like there is one more pointer dereferenced, but it isn't the case. spec3 isn't a value in context, it's just an offset from context. The address you access will therefore be #(context + 2000 + 4*i). There is only one pointer access.
Now you can wonder if #(context + 2000 + 4*i) costs more than #(ptr_int + 4*i). It doesn't, because most architectures, including x86, AMD64 and ARM (that is, 100% of personal devices), have instructions to do accesses with constant offsets. Also, the difference can disappear at soon as you enable trivial optimizations, because context + 2000 can be converted to a single context_2000 (but compilers won't actually do that, since it can only worsen performances).
It does cost more (it has to de-reference the original pointer each iteration), but the cost is probably small, and a halfway decent compiler will make this optimization for you.
Related
I made a function for adding next numbers in the array. Code is very simple, like following
int math(int *address, int size)
{
int sum = 0;
for (int i = 0; i < size; i++)
{
sum += *address;
address++;
}
return sum;
}
During static analysis I found, that there is problem against MISRA rule - which is saying that you can do math only on pointers assigned to an array. Purpose of this function is to use it on arrays, but of course - what I wrote in here is not guarantee that pointer won't be assigned to a variable.
One work-around which I think about is to copy whole table to local area and then sum all elements, but it's rather big operation, wasting lot of uprocessors assets. Do you have any ideas how can I make it better?
This would be from MISRA-C:2004 chapter 17, which was rather irrational about the use of pointers and arrays. This chapter was rewritten from scratch in MISRA-C:2012 (chapter 18). I would strongly recommend to upgrade, since MISRA-C:2004 simply doesn't make much sense here.
As for how to make your code MISRA-C:2004 compliant, do this:
int math(int address[], int size)
{
int sum = 0;
int i; // declaration must be here, MISRA-C:2004 does not allow C99
for (i = 0; i < size; i++)
{
sum += address[i];
}
return sum;
}
Yes it does the very same thing. But at least it made your code slightly more readable.
To make your code even safer, although not compliant with any MISRA, do this:
// better than MISRA-C but not compliant
int math(size_t size, int address[size])
{
int sum = 0;
for (size_t i = 0; i < size; i++)
{
sum += address[i];
}
return sum;
}
Or in case of high integrity systems, you could even do:
int math(size_t size, int (*array)[size])
{
int* address = *array;
...
Both of these alternatives give safer code than MISRA-C.
I'm getting this error:
incompatible pointer types returning 'int [4][2]' from a function with result type 'int *'
When I try to do this
int* getValid(int blank[2]){
int row = blank[0];
int col = blank[1];
static int valid[4][2];
valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;
return valid;
}
I'm trying to return a 2D array that I generate inside the function.
I'm mostly code in Python so arrays in C are kicking my butt..
You cannot pass an array to/from a function in C. But you can pass a pointer. And that can point to an array.
So, you need a function like:
#define COLS 2
int (*getValid(int blank[2]))[COLS]
{
static int valid[4][COLS];
...
return valid;
}
Mind the parenthesis. I also use COLS for the innter dimension's length. This avoids magic numbers, i.e. repeating constants throughout your code. Use that macro for all declarations the array is involved, including the definition.
This is a "function without arguments returning a pointer to an 1D array with COLS ints". For details about arrays and pointers in C, please see a good C book and do some research on your own. Just keep in mind that while they are different types, they have a lot in common in practical use (language mechanisms behind are more difficult to understand).
Simply said, if you use return valid with the above declaration of the function, the name of the array is converted to a pointer to the first element. Which is exactly what you shall return.
The caller need to use the same pointer type (pointer to 1D array) for the result:
int (*arr)[COLS] = getValid(...);
The elements are accessed like for the original array:
arr[row][col]
Additional information: You should not use a static array in the function, unless you want to safe state between calls. Better allocate the array dynamically with malloc:
int (*arr)[COLS];
arr = malloc(sizeof(*arr) * 4); // 4 rows of the inner array
Don't forget to check if malloc failed and take appropriate measures.
Also don't forget to release the dynamically allocated array once you're done with it (but not earlier):
free(arr);
In fact, you must let an n-dimension array decay to a pointer to a n-1 dimension array. And as you use a static array, it is safe to return its address.
The only tricky thing would be to declare a function returning a pointer to an array of size 2, but a typedef can really help here:
typedef int Arr2[2];
Arr2* getValid(int blank[2]){
int row = blank[0];
int col = blank[1];
static int valid[4][2];
valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;
return valid;
}
And you can safely use it like that:
Arr2 * arr = getValid(blank);
for (i=0; i<4; i++) {
for (j=0; j<2; j++) {
printf(" %d", arr[i][j]);
}
putc('\n', stdout);
}
Compiles and runs fine without any warning.
But beware: it is safe only because valid is declared with static storage. Never return a pointer to an automatic array! (use dynamic arrays (allocated with malloc if you do not want static storage)
In C arrays are second class citizens. In order to pass them around you would need to wrap in a structure.
I.e.:
struct t_array42int{int o[4][2];} getValid(int *blank){
int row = blank[0];
int col = blank[1];
static struct t_array42int valid_container;
int (*valid)[2] = valid_container.o;
valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;
return valid_container;
}
Then you can store your function return value like:
struct t_array42int tmp = getValid(something);
Of-course there are ways to simplify this process of "wrapping" but those are often not standard or too obfuscated.
The disadvantage of using structures is that structure types aren't compared by their members layout but instead (normally) by their names. So something like this:
struct { int o[2]; } a;
struct { int o[2]; } b;
a = b; //Error
Is illegal.
You should write:
struct t_array2int { int o[2]; } a;
struct t_array2int b;
a = b; //OK
Instead.
You could also return a pointer to your array instead because it's storage is static (i.e. it won't cease to exist after returning from function):
int (*getValid(int *blank))[2]{
int row = blank[0];
int col = blank[1];
static int valid[4][2];
valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;
return valid;
}
The function prototype:
int (*getValid(int *blank))[2]
Means that if you call your function getValid with a single argument of type int * - getValid(something) and dereference it, *getValid(something) you'll get an array that can't be accessed like (*getValid(something))[2] and so have maximum 2 elements of type int.
Simple instance of the above example will be:
int (*tmp)[2] = getValid(something);
And I also suggest to write your array parameters with their real type (which can never be an array - the compiler is only fooling you into thinking that arrays can be passed by value). I.e.: void f(int a[N]) is adjusted to void f(int *a). And int * is not the same as int [N].
For a newcomer I suggest you remember that arrays are not the same as pointers but are mistreated as such very badly. Also I suggest you to never write functions with array parameters. And if you want to use arrays in a different way then to get pointer to their first element to use structures instead - much safer.
The main thing with array parameter is that:
void f(int a[2])
{
sizeof(a) == sizeof(int *); //evaluates to 1
sizeof(a) != sizeof(int [2]); //evaluates to 1
}
I heard from a programmer (actually an IT teacher) that I should never write this:
void foo(bool foobar) {
if(foobar) {
size_t i;
for (i = 0; i < 42; i++) {
// Do something
}
}
}
But this:
void foo(bool foobar) {
size_t i;
if(foobar) {
for (i = 0; i < 42; i++) {
// Do something
}
}
}
Why?
Moreover, it seems that size_t is also bad because using a unsigned value prevent the compiler to do a good optimization.
That's nonsense. Always reduce the scope of variables as much as possible.
As for performance, it doesn't matter in the slightest. Since a local variable has automatic storage, the compiler will stack your variable just before it is used, no matter where the declaration appears in the source code.
That size_t would prevent the compiler from effectively optimizing your code is also nonsense.
Now what you should do, for scope and style reasons:
for (size_t i = 0; i < 42; i++)
And if this doesn't compile, you need to upgrade to a compiler which isn't older than 15 years.
It is only about subjective matter of coding style. The both codes compiles equally to the same behaviour. One may preffer:
void foo(bool foobar) {
size_t i;
if (foobar) {
for (i = 0; i < 42; i++) {
// Do something
}
}
}
as variable declaration is listed at the top. The second school is to declare variable closest to its usage (this code is perfectly valid in C89), so:
void foo(bool foobar) {
if (foobar) {
size_t i;
for (i = 0; i < 42; i++) {
// Do something
}
}
}
can be preferred instead. Using a C99/C11 compiler it would be even to better to declare it directly in the for loop:
void foo(bool foobar) {
if (foobar) {
for (size_t i = 0; i < 42; i++) {
// Do something
}
}
}
Old-style C (K&R) required all auto variables (in the old sense) to be declared at the beginning of the function after the part that set out the parameter types.
Newer standards (ANSI C) relax that, and modern coding conventions prefer keeping the scope of variables as tight as possible as that increases program stability.
I'd go one stage further and write (possible since C99)
for (size_t i = 0; i < 42; i++)
as then the scope of i is limited to the for loop: there's no danger it will be relied upon in error in other parts of your program.
As for using size_t as the counter, I can't see why that would constrain a compiler's optimisation strategy. In fact, I'd suspect that < could be faster on unsigned types since you don't need to handle a sign bit.
Platform: Linux 3.2.0 x86 (Debian Wheezy)
Compiler: GCC 4.7.2 (Debian 4.7.2-5)
I am writing a function that copies the contents of a buffer to another buffer. I use a void pointer so that the function is not type specific. I have a testable version and it appears that the function is working properly. But I do not know if what I am doing is legal so my question is what are the pitfalls of what I have done if there are any.
#include <stdio.h>
#include <stdlib.h>
void* voidcpy(void *void_ptr, size_t nbytes)
{
char *char_ptr = void_ptr;
char *cpy_char_ptr = NULL;
size_t i = 0;
if((cpy_char_ptr = malloc(nbytes)) == NULL) return NULL;
for(; i < nbytes; i++) cpy_char_ptr[i] = char_ptr[i];
return cpy_char_ptr;
}
int main()
{
short int *intp = NULL;
short int *cpy_intp = NULL;
size_t siz = 5;
int i = 0;
if((intp = malloc(siz * sizeof(short int))) == NULL)
{
perror("(malloc)");
return -1;
}
intp[0] = 0;
intp[1] = 14;
intp[2] = 187;
intp[3] = 12678;
intp[4] = -234;
if((cpy_intp = voidcpy(intp, siz * sizeof(short int))) == NULL)
return -2;
printf("intp = %p\ncpy_intp = %p\n\n", (void*)intp, (void*)cpy_intp);
for(; i < siz; i++) printf("cpy_intp = %i\n", cpy_intp[i]);
free(intp);
free(cpy_intp);
return 0;
}
Yes, this is perfectly legal, in C you can legally assign a void pointer to any other pointer type and you can assign any pointer type to a void pointer.
In C++ this is not allowed. In C++ you would have to use a reinterpret_cast to cast to a different pointer type because the free void pointer casting that is allowed in C is considered a "loop hole" that is easy to make mistakes with.
Of course there is a truth to that idea, if you're not careful you could be doing the wrong thing, e.g. you could easily pass a pointer to a pointer to this function by mistake and then your function will happily overwrite whatever is on the stack beyond that pointer. This is no fault of your implementation however, it's just the way the function is to be used and memcpy behaves no differently.
Nevertheless you would be better off using memcpy instead as this will very likely be much better optimized, though these days the compiler will probably make a pretty decent version out of your code as well.
A few more pointers;
1) you do not need to malloc the original array, you can initialize it statically like so
short int int_arr[] = {
0,
14,
187,
12678,
-234,
};
2) you can then call your function in the following way:
cpy_int_arr = voidcpy(int_arr, sizeof(int_arr));
3) if you don't want to define the array statically, then use the pointer to get the element size, that way you can change the array type without needing to change it somewhere else in the code, which reduces the potential dangers of the "loop hole" void casting:
cpy_intp = voidcpy(intp, siz * sizeof(*intp));
4) you don't need to cast to void* in the printf call
5) try to assign variables immediately and do not put assignments inside of if statements:
char *cpy_char_ptr = malloc(nbytes)
if (cpy_char_ptr == NULL)
return NULL;
6) similarly you can define a iteration variable inside the loop clause:
for(size_t i = 0; i < nbytes; i++) cpy_char_ptr[i] = char_ptr[i];
The reason to define variables as late as possible and initialize them immediately is that you keep the scope of the variables as small as possible and you can not mistakenly use a variable before it is initialized.
7) (personal preference) don't use type names in your identifiers (intp, voidcpy) your code will either become difficult to read/understand if your identifier states a type different from what the variable actually is, (e.g. your type is actually a short int and not an int as the variable name would suggest,) or you will need to change the identifier throughout the entire code whenever you change the type with the possibility of making mistakes.
I must have tried 20 ways of doing this by now. I really need help, no matter what I do i get a error similar to this one.
a value of type "int" cannot be used to initialize an entity of type "int (*)[30]"
i.e. this will get me such an error
int(*array)[160] = malloc((sizeof *array) * 10);
and doing something like this
int** Make2DintArray(int arraySizeX, int arraySizeY) {
int** theArray;
theArray = (int**) malloc(arraySizeX*sizeof(int*));
int i;
for (i = 0; i < arraySizeX; i++)
{
theArray[i] = (int*) malloc(arraySizeY*sizeof(int));
}
return theArray;
}
will get me this
"void *(size_t)" in "memory.c" at line 239 and: "int()"
does anyone have a solution for how to successful allocate a 2dArray of int[160][10]
Try this:
int **array;
array = malloc(rows * sizeof(int *));
for (i = 0; i < rows; i++)
array[i] = malloc(cols * sizeof(int));
// Some testing
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++)
array[i][j] = 0; // or whatever you want
}
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++)
printf("%d ", array[i][j]);
}
In your case rows = 160 and cols = 10. Is one possible solution.
With this approach you can use the two indexes:
Both of these compile fine for me. The first error is common when you forget to #include <stdlib.h> prior to using functions declared within said-same (such as malloc(size_t)), which I did not forget to do.
C has some interesting compile-time behaviors, among them the ability to invoke a function that has never been seen before (neither prototype definition nor implementation). Upon encountering such a call, C assumes the function is:
Something that returns int
Takes an unknown number of arguments, so the caller can pass whatever it wants (including the wrong things).
Eg., the function is implicitly assumed to be of the form:
int func();
Often you won't even notice, save for warnings from your compiler that report something to the effect of:
Warning: implicit declaration of `func` assumed to return `int`
and if you're on-the-ball, you have your warning levels turned up with warnings-as-errors enabled and will catch this.
But what if you don't? And what if the "thing" returned from the function cannot be content-represented by the data size in an implementation int ? What if, for example, int were 32-bit, but data pointers were 64-bit? For example, lets assume char *get_str() is declared in some header file you're not including, and implemented in a .c file you compile and link with your program, that looks like this:
#include <stdio.h>
// Note: NO prototype for get_str
int main()
{
char *s = get_str();
printf("String: %s\n", s);
return 0;
}
Well, the compiler should puke, telling you that int and char* are not compatible (shortly after it warns you get_str is assumed to return int). But what if you force the compiler's hand by telling it to make a char* one way or another:
#include <stdio.h>
// Note: NO prototype for get_str
int main()
{
char *s = (char*)get_str(); // NOTE: added cast
printf("String: %s\n", s);
return 0;
}
Now, without warnings-as-errors enabled, you'll get a implicit declaration warning, and thats it. The code will compile. But will it run ? If sizeof(int) != sizeof(char*), (32-bit vs 64-bit) likely not. The value returned from get_str is a 64-bit pointer, but the caller is assuming only 32-bits is returned, then forcing it to a 64-bit pointer. In short, the cast has hidden the error and opened pandora's box of undefined behavior.
So how does all of this relate to your code? By not including <stdlib.h> the compiler doesn't know what malloc is. So it assumes it is of the form:
int malloc();
Then, by casting the result to (int**) you're telling the compiler "whatever comes out of this, make it a int**". At link time, _malloc is found (no parameter signature via name mangling like C++), wired up, and your program is ready to party. But on your platform int and data pointers are not the same size, thus you end up with several undesirable consequences:
The cast hides the real error.
A bogus pointer is manufactured from half the bits of the real returned pointer.
As a cruel dose of salt to the wound, the allocated memory is leaked, as there are no valid pointers anywhere that reference it (you just destroyed the only one by only keeping half of it).
Probably the most undesirable, the code will exhibit normal behavior if compiled on an implementation where sizeof(int) == sizeof(int**).
So you build this on your 32-bit Debian box, all looks well. You turn in your homework to the professor who builds it on his 64bit Mac and it crashes, you fail the assignment, fail the class, drop out of college, and spend the next ten years petting the cat while watching Seinfeld reruns in your mom's basement wonder what went wrong. Ouch.
Don't treat casting like some silver bullet. It isn't. In C, it is needed far less often than people use it, and if used in the wrong place, can hide catastrophic errors. If you find a point in your code where something won't compile without a hard cast, look again. Unless you're absolutely, positively sure the cast is the right thing to do, odds are its wrong.
In this case it hid the real error, that you neglected to give enough info to your compiler to know what malloc really does.
To allocate the array:
int *array = malloc(sizeof(int) * 160 * 10);
Then use code like:
array[10 * row + column] = value;
(Where row goes from 0 to 159 inclusive and column goes from 0 to 9 inclusive.)
I have a note for rendon's answer:
For his code, Visual C++ says for every "=" operations: error C2440: '=' : cannot convert from 'void *' to 'int **'
By making some changes, it works for me, but I'm not sure that it does the same, so I afraid of editing his code. Instead, here's me code, that seems to work for a first impression.
int **a;
a = (int **)malloc(rows * sizeof(int));
for (i = 0; i < rows; i++)
{
a[i] = (int *)malloc(cols * sizeof(int));
}
for (j=0;j<rows;j++)
{
for (i=0;i<cols;i++)
{
a[i][j] = 2;
}
}
Actually, I did it with a custom struct instead of ints but I think either way should it work.
Don't mind me I'm just adding an example using calloc
void allocate_fudging_array(int R, int C)
{
int **fudging_array = (int **) calloc(R, sizeof(int *));
for(int k = 0; k < R; k++)
{
fudging_array[k] = (int*) calloc(C, sizeof(int));
}
}
// a helper function to print the array
void print2darr(int **arr, int R, int C)
{
for(int i = 0; i < R; i++)
{
for(int j = 0; j < C; j++)
{
printf(" %d ", arr[i][j]);
}
printf("\n");
}
}
2D array to store char *
char ***array;
int rows = 2, cols = 2, i, j;
array = malloc(sizeof(char **)*rows);
for (i = 0; i < rows; i++)
array[i] = malloc(cols * sizeof(char *));
array[0][0] = "asd";
array[0][1] = "qwe";
array[1][0] = "stack";
array[1][1] = "overflow";
for(i=0;i<rows;i++){
for(j=0;j<cols;j++){
printf("%s ",array[i][j]);
}
printf("\n");
}