passing non-global array variable in C - c

C is a reasonably new language to me, most of my programming knowledge is based around Java, or web-based languages - so please be gentle if I come across as a complete noob with this question!
I have an array of type unsigned long, with size 100000, declared in main(). When a certain condition of user input is met, a record() function call is made which initiates some hardware to begin audio recording (not really important to the scope of the question).
At the record() function call, as long as a 'ready' flag in a register is initialised, the contents of the register is copied to an array cell - this process iterates until all 100000 cells of the array have been recorded to.
The array from the record() function now needs be returned to a variable in main(). I have tried this by simply returning a variable of type unsigned long from the method call - but I can't seem to make this work. I have also tried this using pointers - but my inexperience with C is showing when I try this.
My code for using pointers is:
int main(void){
...
unsigned long recordingOne[100000];
unsigned long *ptrOne;
ptrOne = &recordingOne;
...
initiateRecording(ptrOne);
}
void initiateRecording(unsigned long *ptr){
unsigned long returnOne[100000];
for(i = 0; i<100001; i++){
returnOne[i] = AD0DR1 //AD0DR1 corresponds to hardware register
}
*ptr = returnOne;
}
For this I get two warnings:
(in function main) warning: assignment from incompatible pointer type [enabled by default]
(in function initiateRecording) warning: assignment makes integer from pointer without a cast [enabled by default]
When I tried this previously without pointers, I tried passing an array as a parameter, and then returning an array. That looked something like this:
int main(void){
...
unsigned long recordingOne[100000];
...
recordingOne = initiateRecording();
}
unsigned long[] initiateRecording(){
unsigned long toReturnOne[100000];
for(i = 0; i<100001; i++){
toReturnOne[i] = AD0DR1 //AD0DR1 corresponds to hardware register
}
return toReturnOne;
}
The compiler wasn't a fan of this either - I'm struggling to declare a return object of type unsigned long that is also an array.
As always, your help is very much appreciated!

Here is the best method:
int main(void)
{
...
unsigned long recordingOne[100000];
unsigned long *ptrOne; // <<<--- Don't need this
ptrOne = &recordingOne; // <<<--- Don't need this
...
initiateRecording(recordingOne); <<<--- Pass address of array directly
}
void initiateRecording(unsigned long *ptr)
{
for(i = 0; i<100000; i++) <<<---- If i == 100000 undefined behavior, such as a segmentation fault, may occur; change 100001 to 100000
ptr[i] = AD0DR1 // <<<--- write directly to array
}
The accessible elements in recordingOne are from [0] to [99999]

The source of both compiler warnings is the following: when you initialize a C array like int array[100];, the symbol array is a pointer to the first element of the array. So when you write something like int *p = &array, the result is that p points not to the beginning of array, but to the location in memory that holds the pointer to the beginning of array. What you want is int *p = &array[0].
Edit: or int *p = array works just fine too, as pointed out in a comment in another answer.

Related

Warning: Return from incompatible pointer type

The code below is producing a compiler warning: return from incompatible pointer type. The type I'm returning seems to be the issue but I cant seem to fix this warning.
I have tried changing the type of hands to int *. Also have tried returning &hands.
int * dealDeck(int numPlayers, int numCards, int cardDeck[])
{
static int hands[MAX_PLAYERS][MAX_CARDS]={0};
int start = 0;
int end = numCards;
int player, hand, j;
int card;
for(player = 0; player < numPlayers; player++)
{
for(hand = start, j=0; hand < end; hand++,j++)
{
card = cardDeck[hand];
hands[player][j] = card;
}
start = end;
end += numCards;
}
return hands;
}
This function should return a pointer to the array "hands". This array is then passed to another function which will print out its elements.
The hands variable is not an int * this is a int **
So you need to return a int **
This is a 2d array.
First of all, you have declared return type of int *, which would mean, that you are trying to return an array, while you want to return a 2-dimensional array. The proper type for this would usually be int **, but that won't cut it here. You opted to go with static, fixed size array. That means, that you need to return pointer to some structures of size MAX_CARDS * sizeof(int) (and proper type, which is the real problem here). AFAIK, there is no way to specify that return type in C*.
There are many alternatives though. You could keep the static approach, if you specify only up to 1 size (static int *hands[MAX_PLAYERS] or static int **hands), but then you need to dynamically allocate the inner arrays.
The sane way to do it is usually "call by reference", where you define the array normally before calling the function and you pass it as a parameter to the function. The function then directly modifies the outside variables. While it will help massively, with the maintainability of your code, I was surprised to find out, that it doesn't get rid of the warning. That means, that the best solution is probably to dynamically allocate the array, before calling the function and then pass it as an argument to the function, so it can access it. This also solves the question of whether the array needs to be initialized, and whether = {0} is well readable way to do it (for multidimensional array) , since you'll have to initialize it "manually".
Example:
#include <stdio.h>
#include <stdlib.h>
#define PLAYERS 10
#define DECKS 20
void foo(int **bar)
{
bar[0][0] = 777;
printf("%d", bar[0][0]);
/*
* no point in returning the array you were already given
* but for the purposes of curiosity you could change the type from
* void to int ** and "return bar;"
*/
}
int main()
{
int **arr;
arr = malloc(sizeof(int *) * PLAYERS);
for (size_t d = 0; d < DECKS; d++) {
/* calloc() here if you need the zero initialization */
arr[d] = malloc(sizeof(int) * DECKS);
}
foo(arr);
return 0;
}
*some compilers call such type like int (*)[20], but that isn't valid C syntax

array of pointers to array of pointers in C

I have an API which will take triple pointer as an input as below.
extern int myAPI(int ***myData);
Internally "myData" is treated as array of pointer to array of pointers.
So now in another function, i need to call this myAPI. But i am not able to build the array of pointer to array of pointers. Can you please someone help?
I tried similar to below snippet of code. But seen type mismatch compilation error.
int i[10];
int j[10];
int *k[10];
int *l[10];
int *(*m[])[2];
int a = 0;
for (a = 0; a < 10; a++) {
k[a] = &(i[a]);
l[a] = &(j[a]);
}
m[0] = k;
m[1] = l;
a = myAPI(m);
So you want an "array 10 of pointer to array of pointer 20 to int" (you have to specify the dimensions for all but functions arguments where you can omit the outermost dimension only).
That would be:
int *(*a[10])[20];
For such constructs, cdecl is very helpful. The line in quotes is the declaration for the tool.
Note this is what you asked for. Which is not necessarily what you really need. Often such complex constructs are a symptom of a severe design flaw. You might want to reconsider your program code.
Try changing the declaration of m to
int **m[2];

Use typedef for passing parameters by reference

I have this part in instructions of my school project:
In hw_numbers.h define type hw_number_array (for passing arguments to functions by reference). To store numbers in that array, use array of unsigned long.
My friend gave me hint, that it should look like this:
typedef unsigned long hw_number_array[];
Can someone explain me, why should I use this for passing an array to function?
And how can this type even exist without defining actual size of array?
If the size of the array is omitted, this is called an array of unknown bound. There are only certain places where this can be used, but a function parameter is one of them. There is a special rule that says even if a bound is given for an array, the bound is ignored and the parameter is equivalent to a pointer:
void f(int []) // this means void f(int *)
C++ inherited this rule from C. Some programmers consider it helpful for documenting that it is intended that an array is passed for the parameter as opposed to a pointer to a single value.
When calling such a function, it appears that you can pass an array by reference:
{
int a[5];
f(a); // actually passes an int pointer
}
But this is actually an illusion. The array decays to a pointer, and then a pointer is passed instead.
Here's some code you can try:
typedef unsigned long hw_number_array[];
int main()
{
unsigned long myArray[100];
setValue(myArray, 5, 10);
unsigned long value = getValue(myArray, 5);
return 0;
}
unsigned long setValue(hw_number_array a, int index, unsigned long value)
{
a[index] = value;
}
unsigned long getValue(hw_number_array a, int index)
{
return a[index];
}

Passing pointers of arrays in C

So I have some code that looks like this:
int a[10];
a = arrayGen(a,9);
and the arrayGen function looks like this:
int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
arrAddr[counter] = gen(maxNum);
counter++;
}
return arrAddr;
}
Right now the compilier tells me "warning: passing argument 1 of ‘arrayGen’ makes integer from pointer without a cast"
My thinking is that I pass 'a', a pointer to a[0], then since the array is already created I can just fill in values for a[n] until I a[n] == '\0'. I think my error is that arrayGen is written to take in an array, not a pointer to one. If that's true I'm not sure how to proceed, do I write values to addresses until the contents of one address is '\0'?
The basic magic here is this identity in C:
*(a+i) == a[i]
Okay, now I'll make this be readable English.
Here's the issue: An array name isn't an lvalue; it can't be assigned to. So the line you have with
a = arrayGen(...)
is the problem. See this example:
int main() {
int a[10];
a = arrayGen(a,9);
return 0;
}
which gives the compilation error:
gcc -o foo foo.c
foo.c: In function 'main':
foo.c:21: error: incompatible types in assignment
Compilation exited abnormally with code 1 at Sun Feb 1 20:05:37
You need to have a pointer, which is an lvalue, to which to assign the results.
This code, for example:
int main() {
int a[10];
int * ip;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
return 0;
}
compiles fine:
gcc -o foo foo.c
Compilation finished at Sun Feb 1 20:09:28
Note that because of the identity at top, you can treat ip as an array if you like, as in this code:
int main() {
int a[10];
int * ip;
int ix ;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
for(ix=0; ix < 9; ix++)
ip[ix] = 42 ;
return 0;
}
Full example code
Just for completeness here's my full example:
int gen(int max){
return 42;
}
int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
arrAddr[counter] = gen(maxNum);
counter++;
}
return arrAddr;
}
int main() {
int a[10];
int * ip;
int ix ;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
for(ix=0; ix < 9; ix++)
ip[ix] = 42 ;
return 0;
}
Why even return arrAddr? Your passing a[10] by reference so the contents of the array will be modified. Unless you need another reference to the array then charlies suggestion is correct.
Hmm, I know your question's been answered, but something else about the code is bugging me. Why are you using the test against '\0' to determine the end of the array? I'm pretty sure that only works with C strings. The code does indeed compile after the fix suggested, but if you loop through your array, I'm curious to see if you're getting the correct values.
I'm not sure what you are trying to do but the assignment of a pointer value to an array is what's bothering the compiler as mentioned by Charlie. I'm curious about checking against the NUL character constant '\0'. Your sample array is uninitialized memory so the comparison in arrayGen isn't going to do what you want it to do.
The parameter list that you are using ends up being identical to:
int* arrayGen(int *arrAddr, int maxNum)
for most purposes. The actual statement in the standard is:
A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
If you really want to force the caller to use an array, then use the following syntax:
void accepts_pointer_to_array (int (*ary)[10]) {
int i;
for (i=0; i<10; ++i) {
(*ary)[i] = 0; /* note the funky syntax is necessary */
}
}
void some_caller (void) {
int ary1[10];
int ary2[20];
int *ptr = &ary1[0];
accepts_pointer_to_array(&ary1); /* passing address is necessary */
accepts_pointer_to_array(&ary2); /* fails */
accepts_pointer_to_array(ptr); /* also fails */
}
Your compiler should complain if you call it with anything that isn't a pointer to an array of 10 integers. I can honestly say though that I have never seen this one anywhere outside of various books (The C Book, Expert C Programming)... at least not in C programming. In C++, however, I have had reason to use this syntax in exactly one case:
template <typename T, std::size_t N>
std::size_t array_size (T (&ary)[N]) {
return N;
}
Your mileage may vary though. If you really want to dig into stuff like this, I can't recommend Expert C Programming highly enough. You can also find The C Book online at gbdirect.
Try calling your parameter int* arrAddr, not int arrAddr[]. Although when I think about it, the parameters for the main method are similar yet that works. So not sure about the explanation part.
Edit: Hm all the resources I can find on the internet say it should work. I'm not sure, I've always passed arrays as pointers myself so never had this snag before, so I'm very interested in the solution.
The way your using it arrayGen() doesn't need to return a value. You also need to place '\0' in the last element, it isn't done automatically, or pass the index of the last element to fill.
#jeffD
Passing the index would be the preferred way, as there's no guarantee you won't hit other '\0's before your final one (I certainly was when I tested it).

Solution for "dereferencing `void *' pointer" warning in struct in C?

I was trying to create a pseudo super struct to print array of structs. My basic
structures are as follows.
/* Type 10 Count */
typedef struct _T10CNT
{
int _cnt[20];
} T10CNT;
...
/* Type 20 Count */
typedef struct _T20CNT
{
long _cnt[20];
} T20CNT;
...
I created the below struct to print the array of above mentioned structures. I got dereferencing void pointer error while compiling the below code snippet.
typedef struct _CMNCNT
{
long _cnt[3];
} CMNCNT;
static int printCommonStatistics(void *cmncntin, int cmncnt_nelem, int cmncnt_elmsize)
{
int ii;
for(ii=0; ii<cmncnt_nelem; ii++)
{
CMNCNT *cmncnt = (CMNCNT *)&cmncntin[ii*cmncnt_elmsize];
fprintf(stout,"STATISTICS_INP: %d\n",cmncnt->_cnt[0]);
fprintf(stout,"STATISTICS_OUT: %d\n",cmncnt->_cnt[1]);
fprintf(stout,"STATISTICS_ERR: %d\n",cmncnt->_cnt[2]);
}
return SUCCESS;
}
T10CNT struct_array[10];
...
printCommonStatistics(struct_array, NELEM(struct_array), sizeof(struct_array[0]);
...
My intention is to have a common function to print all the arrays. Please let me know the correct way of using it.
Appreciate the help in advance.
Edit: The parameter name is changed to cmncntin from cmncnt. Sorry it was typo error.
Thanks,
Mathew Liju
I think your design is going to fail, but I am also unconvinced that the other answers I see fully deal with the deeper reasons why.
It appears that you are trying to use C to deal with generic types, something that always gets to be hairy. You can do it, if you are careful, but it isn't easy, and in this case, I doubt if it would be worthwhile.
Deeper Reason: Let's assume we get past the mere syntactic (or barely more than syntactic) issues. Your code shows that T10CNT contains 20 int and T20CNT contains 20 long. On modern 64-bit machines - other than under Win64 - sizeof(long) != sizeof(int). Therefore, the code inside your printing function should be distinguishing between dereferencing int arrays and long arrays. In C++, there's a rule that you should not try to treat arrays polymorphically, and this sort of thing is why. The CMNCNT type contains 3 long values; different from both the T10CNT and T20CNT structures in number, though the base type of the array matches T20CNT.
Style Recommendation: I strongly recommend avoiding leading underscores on names. In general, names beginning with underscore are reserved for the implementation to use, and to use as macros. Macros have no respect for scope; if the implementation defines a macro _cnt it would wreck your code. There are nuances to what names are reserved; I'm not about to go into those nuances. It is much simpler to think 'names starting with underscore are reserved', and it will steer you clear of trouble.
Style Suggestion: Your print function returns success unconditionally. That is not sensible; your function should return nothing, so that the caller does not have to test for success or failure (since it can never fail). A careful coder who observes that the function returns a status will always test the return status, and have error handling code. That code will never be executed, so it is dead, but it is hard for anyone (or the compiler) to determine that.
Surface Fix: Temporarily, we can assume that you can treat int and long as synonyms; but you must get out of the habit of thinking that they are synonyms, though. The void * argument is the correct way to say "this function takes a pointer of indeterminate type". However, inside the function, you need to convert from a void * to a specific type before you do indexing.
typedef struct _CMNCNT
{
long count[3];
} CMNCNT;
static void printCommonStatistics(const void *data, size_t nelem, size_t elemsize)
{
int i;
for (i = 0; i < nelem; i++)
{
const CMNCNT *cmncnt = (const CMNCNT *)((const char *)data + (i * elemsize));
fprintf(stdout,"STATISTICS_INP: %ld\n", cmncnt->count[0]);
fprintf(stdout,"STATISTICS_OUT: %ld\n", cmncnt->count[1]);
fprintf(stdout,"STATISTICS_ERR: %ld\n", cmncnt->count[2]);
}
}
(I like the idea of a file stream called stout too. Suggestion: use cut'n'paste on real source code--it is safer! I'm generally use "sed 's/^/ /' file.c" to prepare code for cut'n'paste into an SO answer.)
What does that cast line do? I'm glad you asked...
The first operation is to convert the const void * into a const char *; this allows you to do byte-size operations on the address. In the days before Standard C, char * was used in place of void * as the universal addressing mechanism.
The next operation adds the correct number of bytes to get to the start of the ith element of the array of objects of size elemsize.
The second cast then tells the compiler "trust me - I know what I'm doing" and "treat this address as the address of a CMNCNT structure".
From there, the code is easy enough. Note that since the CMNCNT structure contains long value, I used %ld to tell the truth to fprintf().
Since you aren't about to modify the data in this function, it is not a bad idea to use the const qualifier as I did.
Note that if you are going to be faithful to sizeof(long) != sizeof(int), then you need two separate blocks of code (I'd suggest separate functions) to deal with the 'array of int' and 'array of long' structure types.
The type of void is deliberately left incomplete. From this, it follows you cannot dereference void pointers, and neither you can take the sizeof of it. This means you cannot use the subscript operator using it like an array.
The moment you assign something to a void pointer, any type information of the original pointed to type is lost, so you can only dereference if you first cast it back to the original pointer type.
First and the most important, you pass T10CNT* to the function, but you try to typecast (and dereference) that to CMNCNT* in your function. This is not valid and undefined behavior.
You need a function printCommonStatistics for each type of array elements. So, have a
printCommonStatisticsInt, printCommonStatisticsLong, printCommonStatisticsChar which all differ by their first argument (one taking int*, the other taking long*, and so on). You might create them using macros, to avoid redundant code.
Passing the struct itself is not a good idea, since then you have to define a new function for each different size of the contained array within the struct (since they are all different types). So better pass the contained array directly (struct_array[0]._cnt, call the function for each index)
Change the function declaration to char * like so:
static int printCommonStatistics(char *cmncnt, int cmncnt_nelem, int cmncnt_elmsize)
the void type does not assume any particular size whereas a char will assume a byte size.
You can't do this:
cmncnt->_cnt[0]
if cmnct is a void pointer.
You have to specify the type. You may need to re-think your implementation.
The function
static int printCommonStatistics(void *cmncntin, int cmncnt_nelem, int cmncnt_elmsize)
{
char *cmncntinBytes;
int ii;
cmncntinBytes = (char *) cmncntin;
for(ii=0; ii<cmncnt_nelem; ii++)
{
CMNCNT *cmncnt = (CMNCNT *)(cmncntinBytes + ii*cmncnt_elmsize); /* Ptr Line */
fprintf(stdout,"STATISTICS_INP: %d\n",cmncnt->_cnt[0]);
fprintf(stdout,"STATISTICS_OUT: %d\n",cmncnt->_cnt[1]);
fprintf(stdout,"STATISTICS_ERR: %d\n",cmncnt->_cnt[2]);
}
return SUCCESS;
}
Works for me.
The issue is that on the line commented "Ptr Line" the code adds a pointer to an integer. Since our pointer is a char * we move forward in memory sizeof(char) * ii * cmncnt_elemsize, which is what we want since a char is one byte. Your code tried to do an equivalent thing moving forward sizeof(void) * ii * cmncnt_elemsize, but void doesn't have a size, so the compiler gave you the error.
I'd change T10CNT and T20CNT to both use int or long instead of one with each. You're depending on sizeof(int) == sizeof(long)
On this line:
CMNCNT *cmncnt = (CMNCNT *)&cmncnt[ii*cmncnt_elmsize];
You are trying to declare a new variable called cmncnt, but a variable with this name already exists as a parameter to the function. You might want to use a different variable name to solve this.
Also you may want to pass a pointer to a CMNCNT to the function instead of a void pointer, because then the compiler will do the pointer arithmetic for you and you don't have to cast it. I don't see the point of passing a void pointer when all you do with it is cast it to a CMNCNT. (Which is not a very descriptive name for a data type, by the way.)
Your expression
(CMNCNT *)&cmncntin[ii*cmncnt_elmsize]
tries to take the address of cmncntin[ii*cmncnt_elmsize] and then cast that pointer to type (CMNCNT *). It can't get the address of cmncntin[ii*cmncnt_elmsize] because cmncntin has type void*.
Study C's operator precedences and insert parentheses where necessary.
Point of Information: Internal Padding can really screw this up.
Consider struct { char c[6]; }; -- It has sizeof()=6. But if you had an array of these, each element might be padded out to an 8 byte alignment!
Certain assembly operations don't handle mis-aligned data gracefully. (For example, if an int spans two memory words.) (YES, I have been bitten by this before.)
.
Second: In the past, I've used variably sized arrays. (I was dumb back then...) It works if you are not changing type. (Or if you have a union of the types.)
E.g.:
struct T { int sizeOfArray; int data[1]; };
Allocated as
T * t = (T *) malloc( sizeof(T) + sizeof(int)*(NUMBER-1) );
t->sizeOfArray = NUMBER;
(Though padding/alignment can still screw you up.)
.
Third: Consider:
struct T {
int sizeOfArray;
enum FOO arrayType;
union U { short s; int i; long l; float f; double d; } data [1];
};
It solves problems with knowing how to print out the data.
.
Fourth: You could just pass in the int/long array to your function rather than the structure. E.g:
void printCommonStatistics( int * data, int count )
{
for( int i=0; i<count; i++ )
cout << "FOO: " << data[i] << endl;
}
Invoked via:
_T10CNT foo;
printCommonStatistics( foo._cnt, 20 );
Or:
int a[10], b[20], c[30];
printCommonStatistics( a, 10 );
printCommonStatistics( b, 20 );
printCommonStatistics( c, 30 );
This works much better than hiding data in structs. As you add members to one of your struct's, the layout may change between your struct's and no longer be consistent. (Meaning the address of _cnt relative to the start of the struct may change for _T10CNT and not for _T20CNT. Fun debugging times there. A single struct with a union'ed _cnt payload would avoid this.)
E.g.:
struct FOO {
union {
int bar [10];
long biff [20];
} u;
}
.
Fifth:
If you must use structs... C++, iostreams, and templating would be a lot cleaner to implement.
E.g.:
template<class TYPE> void printCommonStatistics( TYPE & mystruct, int count )
{
for( int i=0; i<count; i++ )
cout << "FOO: " << mystruct._cnt[i] << endl;
} /* Assumes all mystruct's have a "_cnt" member. */
But that's probably not what you are looking for...
C isn't my cup o'java, but I think your problem is that "void *cmncnt" should be CMNCNT *cmncnt.
Feel free to correct me now, C programmers, and tell me this is why java programmers can't have nice things.
This line is kind of tortured, don'tcha think?
CMNCNT *cmncnt = (CMNCNT *)&cmncntin[ii*cmncnt_elmsize];
How about something more like
CMNCNT *cmncnt = ((CMNCNT *)(cmncntin + (ii * cmncnt_elmsize));
Or better yet, if cmncnt_elmsize = sizeof(CMNCNT)
CMNCNT *cmncnt = ((CMNCNT *)cmncntin) + ii;
That should also get rid of the warning, since you are no longer dereferencing a void *.
BTW: I'm not real sure why you are doing it this way, but if cmncnt_elmsize is sometimes not sizeof(CMNCNT), and can in fact vary from call to call, I'd suggest rethinking this design. I suppose there could be a good reason for it, but it looks really shaky to me. I can almost guarantee there is a better way to design things.

Resources