This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
pointer arithmetic in C for getting a string
I am a newbie in C and I would like to get the elements of an array with a function, I have tried different options, but I still do not get the elements.
My function is:
void getelements(int *a, int cl)
{
int *p;
for (p=&a[0];p<&a[cl];p++)
{
printf("%d\n",*p);
}
}
I know that the solution should work like that, but it only prints the first element and then memory positions. I am calling my function with:
int v={10,12,20,34,45};
getelements(&v,5);
Any help? I need to use arithmetic of pointers.
Thanks
First, Please don't update code to fix bugs while a question is open. It makes most of the current answers meaningless, doesn't grant credit where it is due to the person(s) that solved one or more issues in your prior code, and makes the casual reader looking for a related problem to their own completely confused by both the question and the answers therein. If you want to amend an update do so in addition to the original problem, but if it an entirely different issue, then mark as answered, give credit where it is due, and open a new question with your new code and different problem(s) (ideally, anyway).
As written now, your function is fine. But your real issue is this:
// compile with -Wall -Werror and look at the warning here
int v={10,12,20,34,45}; // <== WRONG
getelements(&v,5); // <== Harmless, but bad form.
This should be like this instead, assuming you want to print all elements in the array:
int v[] = {10,12,20,34,45};
getelements(v, sizeof(v)/sizeof(v[0]));
Note the [] following your array. Without it, the &v was masking what would have been a big-fat warning or error from the compiler that int is being passed as an int *. Furthermore, if you compile your prior code with full warnings treated as errors (-Wall -Werror for gcc) you will get an error like the following on your v declaration line:
main.c:116:15: Excess elements in scalar initializer
In other words, everything past the first element was ignored, and thus your pointer was running off into undefined behavior land. Changing the declaration and invocation to what I have above will address this as well as ensure you don't make that mistake again, since sizeof(v[0]) won't even compile unless v is an array or pointer type. The latter can still cause headaches when you use a pointer rather than an array with such a calculation, but thats something you just have to discipline yourself against doing in C.
try this and let me know if that works.
void getelements(int *a)
{
int *p;
int l=5;
for (p=a;p<a+l;p++)
{
printf("%d\n",*p);
}
}
It's best to pass in the length of the array along with the array itself.
#include <stdlib.h>
#include <stdio.h>
void get_elements(int* values, int length)
{
int i;
for (i = 0; i < length; ++i)
{
printf("%d\n", values[i]);
}
}
int main(int argc, char** argv)
{
int vals[3];
vals[0] = 0;
vals[1] = 1;
vals[2] = 2;
get_elements(vals, 3);
getchar();
return 0;
}
Using the code similar to your original post (before the addition of the array length as a method parameter), you could do the follow (which is a bit convoluted if you ask me).
void get_elements(int* values, int length)
{
int *p;
for (p = &values[0]; p < &values[length]; p++)
{
printf("%d\n", *p);
}
}
Actually you are passing array address in
getelements(&v,5)
in function
getelements()
you are treating it like an array!!!
void getelements(int *a, int cl)
{
int *p;
for (p=a;p<a+cl;p++)
{
printf("%d\n",*p);
}
}
Let me know if you are cleared conceptually!!!
As per my knowledge and seeing your code.you have hardcoded the length of array to 5. I think you can also pass array length as a parameter to function; or you can use this function and see if it gives the desired result
void getelements(int *a)
{
int *p;
int i = 0;
int l=5;
p = a
for (i = 0;i<l;i++)
{
printf("%d\n",*(p + i));
}
}
Related
I am currently reading understanding pointers in c, am at the section were the author talks about passing arrays to functions. Out of all the bellow patterns which is best to use and why ? , does it have anything to do with optimisation ?
#include <stdio.h>
void passAsPointerWithSize(int * arr, int size) {
for ( int i = 0; i < size; i++ ) {
printf("%d\n", arr[i]);
}
}
void passAsPointerWithoutSize(int * arr) {
while ( *arr ) {
printf("%d\n", *arr);
arr++;
}
}
void passWithoutPointerWithSize( int arr [] , int size) {
for ( int i = 0; i <= size; i++ ) {
printf("%d\n", arr[i]);
}
}
void passWithoutPointerUsingWhile(int arr []) {
int i = 1;
while ( arr[i] ) {
printf("%d\n", arr[i++]);
}
}
int main() {
int size = 5;
int arr[5] = { 1, 2, 3, 4 , 5};
passAsPointerWithSize(arr, size);
passAsPointerWithoutSize(arr);
passWithoutPointerWithSize(arr, size);
passWithoutPointerUsingWhile(arr);
}
i compiled it with -std=gnu11 -O3
In the context of function parameters, int arr [] is the same as int *arr because when an array is passed as a function argument to a function parameter, it decays into a pointer to its first element.
So the following declaration:
void foo(int * arr, int size);
is equivalent to:
void foo(int arr[], int size);
When it comes to the question whether you need the size parameter, you need it in order to determine the length of the array, unless:
there is a special value stored in the array that act as an indicator for the end of array (the callee would be responsible for checking against this indicator).
the length of the array is already known to the caller.
Otherwise, how could you possibly know how many elements the array contains?
Out of all the bellow patterns which is best to use and why ?
With the points above in mind, the only thing you can always choose is whether to use the int * syntax or the int [] one for the function parameter.
Although both are equivalent (as explained above), some people may argue that using int * could suggest that there is at most one element, whereas int [] could suggest thet there there is at least one element and there could be more than one.
does it have anything to do with optimization ?
No, or at least, not directly, whether you need the size parameter is actually a matter of whether the size of the array is known by the caller or it can be obtained by means of a stored end-of-array indicator.
First see which one is correct! (based on what you posted)
void passAsPointerWithSize(int * arr, int size) {
for ( int i = 0; i < size; i++ ) {
printf("%d\n", arr[i]);
}
}
This is the one not invoking Undefined Behavior.
The ones using while won't stop unless they get an element having value 0. What if the array has no 0's ? Then it will access way beyond the memory (which is the case here). Perhaps this echos back to a time when strings used to be marked with zeros at their end, in any case, it's bad practice.
The other for loop is looping till index<=size accessing array index out of bounds when index = size, again, undefined behavior.
Now back to your question..
The syntax func(int arr[],..) is the same as func(int* arr,...) on the context of passing a 1D-array to a function. Arrays are passed as pointers - it doesn't matter how you specify the signature.
Looping? - it's just a matter of choice.
Typos and other things...
Typos are the <= or the i=1 initialization in one of the functions. did you not want to print the 0-th element? Well i=1 and then you start looping - it missed the 0-th element.
A compiler, when passed an array, deals with a pointer to the first element of the array no matter how you write it so the form doesn't matter
How do I know the size of the array passed?
In any of the cases - when you pass an array to a function as a pointer - there is no way to know the length of the array unless you have some placeholder which marks the end of the array. If that is not the case then you have to obviously somehow know the length of it - which is what you do when you pass a parameter named size in the function.
Readability + Choice + ...
Writing it as arr[] can be used to convey the meaning that it is an array when we will deal with that pointer. You may skim through the code and get an idea about what it is getting as arguments and what it will possibly do. One may argue that a comment can still serve that purpose - that's where choice comes into the picture.
Yeah, some of them won't work (what do you mean by the condition *arr for instance? are you trying to bring back null terminated strings? don't!)
But, actually the fastest one (barring some crazy compiler optimization which I for one have not seen in practice) if you don't care about order is iterating backwards
void passAsPointerWithSize(int *arr, int size) {
for ( int i = size - 1; i > 0; i-- ) {
printf("%d\n", arr[i]);
}
}
That's because it saves a whole CPU clock cycle every loop, since after you reduce i (i--) the answer of comparing to zero (i > 0) is already stored in the registers
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];
So, in my function when I try to return a long, it acts like I'm returning an int. This mostly comes into play when I'm trying to return a long that has more than 10 digits, it will return an int limited to 10 digits.
For example my code is trying to find the greatest number within an array of longs so,
#include<stdio.h>
#include<stdlib.h>
long maximum(long arr[])
{
long i, max;
for(i = 0; i < sizeof(arr); i++)
{
//This sets the initial number to the maximum
if(i == 0)
{
max = arr[0]
}
else if(arr[i] > max)
{
max = arr[i];
}
}
return max;
}
When I do a printf in the array right before the return it prints out the correct long with all its digits, but when I return it and try to use this function to return the long in another function then it will only return an int limited to 10 digits. I feel like there might be something obvious I'm missing but I don't know what it is.
My guess is that you did not explicitely tell the compiler that the signature would return long from your other instanciation unit. Just state somewhere in your other code that the function really is long maximum(long arr[]). Using gcc, you can even use -Wimplicit-function-declaration
You are not posting the code that processes the return value. I assume that's because you're sure that's not where the bug is. So it's quite obvious that this is where the bug is.
Strategy for finding bugs: You start with the assumption that unknown evil forces keep your program from working and start fluffing around (that's your current stage). In that stage, you're not going to find the problem. The second stage is that you realise that you made a mistake and your job is to find where the mistake is. Emphasis is that you made the mistake. Your code is not correct. So look at it under the assumption that your code is wrong. Look at it under the assumption that code where you are 100% sure that it is correct is actually wrong.
If that strategy doesn't work, imagine that the code isn't written by you and therefore bug free, but written by your worst enemy who will finally get fired by your boss if you can find the bug in his code. That will help.
The clou is that a long has a size of 32bit (−2147483647,+2147483647) that means you aren't able to process larger numbers.
Try to use 'long long int' instead!
For the sizeof operator to give the actual size of the array, you need to:
Allocate the array statically
Refer to the array within its scope of declaration
For example:
void func()
{
int arr[10];
int total_size = sizeof(arr);
int num_of_elements = sizeof(arr)/sizeof(*arr);
...
}
An example of when the array is not statically allocated:
void func()
{
int* arr = malloc(sizeof(int)*10);
int total_size = sizeof(arr); // will give you the size of 'int*'
...
}
An example of when the array is not within its scope of declaration:
void func(int arr[]) // same as 'int* arr'
{
int total_size = sizeof(arr); // will give you the size of 'int*'
...
}
Please note that for your specific purpose, you actually need the number of elements in the array and not its total size (as shown in the first example above).
In addition to all of that, sizeof(long) is not necessarily larger than sizeof(int) on every platform, so you might need to use long long instead.
I know it's simple, but I can't seem to make this work.
My function is like so:
int GefMain(int array[][5])
{
//do stuff
return 1;
}
In my main:
int GefMain(int array[][5]);
int main(void)
{
int array[1800][5];
GefMain(array);
return 0;
}
I referred to this helpful resource, but I am still getting the error "warning: passing argument 1 of GefMain from incompatible pointer type." What am I doing wrong?
EDIT:
The code is in two files, linked together by the compiler. I am not using gcc. The above code is exactly what I have, except the function is declared as "extern int" in the main. Thank you all for your time.
The code is fine. In a single file, this compiles fine for me with gcc.
int g(int arr[][5])
{
return 1;
}
int main()
{
int array[1800][5];
g(array);
return 0;
}
My guess is that you're #includeing the wrong file -- perhaps one that had a different declaration for GefMain. Or perhaps you just haven't saved the file that declared GefMain, so it still has an argument of int [][3], for instance, which would cause the warning.
I would suggest that you post the entire code to reproduce the problem (after you strip out everything that's unneeded to reproduce it, of course). But chances are, at that point, you'll have solved it yourself.
It compiles rightly even with -std=c99 -pedantic options. And it looks right anyway... Is it really the code you want we check? Compiler you're using...?
gcc will have extensions for what you've had (and others have had sucess with). Instead try this, it'll be more portable to other c compilers:
int g(int (* arr)[5])
{
return 1;
}
int main()
{
int array[1800][5];
g(array);
return 0;
}
or better yet;
int g(int (* arr)[5], int count)
{
return 1;
}
int main()
{
int array[1800][5];
g(array, sizeof(array)/sizeof(* array));
return 0;
}
You're getting a warning because an array of any dimension becomes a pointer when it is passed as an arguement, the above gives the compiler a clue that it should expect such.
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).