I'm getting a compile errors, that I can't really fix. I need to create a program that initializes an in array, then write a biggest function that takes 2 parameters, an array and it's length and returns the index of the largest element in the array. I will then call this function from main. Can anyone tell me what is the problem?
errors:part1.c: part1.c: In function 'main':
part1.c:6:3: warning: implicit declaration of function 'largest'
part1.c:7:23: error: expected expression before ']' token
part1.c: In function 'largest':
part1.c:17:4: warning: statement with no effect
Thanks!
#include <stdio.h>
int main()
{
int myArray[]={1,2,3,4,5,6};
largest(myArray,6);
printf("%d",myArray[]);
return 0;
}
int largest(int array[], int length)
{
length = sizeof(array)/sizeof(array[0]);
int i = 1;
int max = array[0];
for(i; i<length; i++)
{
if(max < array[i])
{
max = array[i];
}
}
return max;
}
ISSUE 1
You use largest() in main() before you define it. Use a prototype, or move the definition above main().
ISSUE 2
In:
length = sizeof(array)/sizeof(array[0]);
You declare length as int length, but assign to it something of type size_t. That caused the error error: 'length' redeclared as different kind of symbol in the original version of your question.
ISSUE 3
In
for(i; i<length; i++)
you do not assign a value to i. Did you mean
for(i=0; i<length; i++)
? Although you did previously assign a value to i, I believe this is causing warning: statement with no effect (though hard to be sure without line numbers in the provided code).
Also, arrays in C are 0-based. You probably want to initialize i to 0 rather than 1.
ISSUE 4
In the line
printf("%d",myArray[]);
you use %d as a formatting specifier, which means that the supplied argument is expected to be an integer value. You supply an array instead.
C compiles your code in one pass. This means that everything should be defined before it is used. Your function largest is defined after its use, therefore once the compiler sees
largest(myArray,6);
it still doesn't know that largest exists!
The solution would be to either move the definition of largest above main, or better, forward declare the function:
#include <stdio.h>
int largest(int array[], int length);
int main()
{
int myArray[]={1,2,3,4,5,6};
largest(myArray,6);
printf("%d",myArray[]);
return 0;
}
int largest(int array[], int length)
{
/* implementation of largest */
}
Also, the sizeof(array) will not give you the number of elements in largest because that information is lost upon function call. You could move that expression up in the function call to compute and pass the length parameter:
largest(myArray,sizeof(myArray)/sizeof(myArray[0]));
This may also be a typo, but you probably meant to store and print the maximum value:
int max = largest(myArray,sizeof(myArray)/sizeof(myArray[0]));
printf("%d\n",max);
Put a declaration of largest() before main() to resolve the implicit declaration warning:
int largest(int array*, int length);
int main()
The error error: expected expression before ']' token is caused by:
printf("%d",myArray[]);
To print the largest value, you need to store the result of largest() or use it as an argument to printf():
printf("%d", largest(myArray, 6));
This is not what you expect:
length = sizeof(array)/sizeof(array[0]);
as arrays decays to pointers when passed as arguments. It is equivalent to:
length = sizeof(int*)/sizeof(int);
Just use the length argument to control the iteration. Recommend make the arguments to largest() const as the function does not modify them.
The warning: statement with no effect is caused by the i; in the for:
for(i; i<length; i++)
change to:
for(; i<length; i++)
or:
for(i = 0; i<length; i++)
or if C99:
for(int i = 0; i<length; i++)
You could also just move the definition of largest() above the definition of main() and it would work.
Many people have pointed out many issues but surprised no one has mentioned this:
int largest(int array[], int length)
{
length = sizeof(array)/sizeof(array[0]);
Nope, sizeof does not do what you appear to think it does here. It does not magically know the size of your allocations, only takes the size of the underlying type. What you have done is equivalent to sizeof(int*)/sizeof(int).
You should trust the length parameter the caller gave you. There's no way to get the actual size of the array using sizeof, only let the caller tell you how big it is.
You have an error and warnings .. the error is clearly more important.
printf("%d",myArray[]);
the %d format specification implies you want to write an int value, this is not the case, and the likely cause of your error.
There are other warnings that deserved your attention, such as not providing a function prototype for your 'largest` function etc, but those are secondary to fixing the error that prevents compilation.
Of course the warnings should also be eliminated, or a conscious decision should be made to ignore them after examining them.
Related
I started learning C language a week ago.
Just for the test I decided to write a tictactoe game.
I have a field.
int field[3][3];
And a function printField
void printField(int field[3][3]){
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
printf("%i", field[i][j]);
}
printf("\n");
}}
It's working in main like this:
int main(){
printField(field);}
BUT if I change
void printField(int field){...}
or
void printField(int field[][]){...}
It gives me a bunch of errors:
subscripted value is neither array nor pointer nor vector
passing argument 1 of ‘printField’ makes integer from pointer without a cast
note: expected ‘int’ but argument is of type ‘int (*)[3]’
Why can't I pass the array like this?
Are there any more ways to pass it?
The function is independent of any call to the function. So the function cannot guess from the rest of the program what the array size is. In the function body you have to have constants or variables to represent all dimensions.
You can use variables for this instead of fixed size:
void printField(int r, int c, int field[r][c])
{
for(int i = 0; i < r; i++)
for(int j = 0; j < c; j++)
printf("%i", field[i][j]);
printf("\n");
}
And to call the function:
printField(3, 3, field);
You can compute the dimensions from the array's name. Using a macro confines the ugly syntax:
#define printField(a) printField( sizeof(a)/sizeof((a)[0]), sizeof((a)[0]) / sizeof((a)[0][0]), (a) )
int f1[3][3] = { 0 };
printField(f1);
int f2[4][5] = { 0 };
printField(f2);
When you write an array as a function, the compiler will silently "adjust" that array and replace it with a pointer to the first element. So when you write void func (int x[3]) the compiler silently replaces this with void func (int* x) where the pointer points at the first item of the array.
The reason why C was designed this way is not avoid having large arrays getting pushed on the stack, which would be slow and memory-consuming.
In your case, the function void printField(int field[3][3]) gets silently adjusted behind the lines to
void printField(int (*field)[3])
which is an array pointer pointing at the first element, which is a int[3] array. Which can still be used as field[i][j], so all is well. You can pretend that it is an array inside the function.
void printField(int field) obviously doesn't make any sense. This is not an array but a single item. You can't use [] on a plain int and that's what the compiler is telling you: "subscripted value is neither array nor pointer nor vector".
void printField(int field[][]){...} doesn't work either, because an empty [] means "declare an array of incomplete type". It can't be used before the array size is defined.
In case of void printField(int field[]) this happens to work because of the above mentioned "array adjustment" rule of functions. The compiler doesn't have to know the array size, because it just replaces the array with int* anyway.
But in the case with two unknown dimensions, the compiler tries to adjust int field[][] to int (*field)[]. This is a pointer to an array of incomplete type and can't be used by the function.
You could however do int field[][3] and it will work just fine.
In C You can pass you array like this
void printField(int **field){...}
it's much better to work with pointeur than to work with static array :)
I'm trying to fill an array with numbers from 1-100 with this code:
#include <stdio.h>
int main()
{
int num[100];
int i = 0;
for (i = 0; i < 100; i++)
{
int num[i] = i+1;
}
}
but I'm getting this error:
c:18:13: error: variable-sized object may not be initialized
I'm still relatively new to programming so I'm not sure what this means. Can you tell me?
Replace this
int num[i] = i+1;
For this:
num[i] = i+1;
You already declare the array on the top int num[100];
First you declare the array, and then you iterate over it inside the loop.
Since you are new, it is preferable you start by reading a good book about the subject my recommendation.
The problem is the int in int num[i] = i+1. The compiler thinks you're trying to declare a new array (also called num) with i elements in it (that's the variable-sized object part). Just remove the int from that line.
You are declaring the array again in the loop:
int num[i] = i+1;
Anyway, this is the error in your code but the problem for the compiler is not there: it gives you that error because that's not a valid declaration with initialization for an array. If you just write int num[i]; the code it's valid code and it will compile without error (well, only from C99, old C89 doesn't support variable-length arrays). This is what the compiler recognizes and tries to report.
I have tried (sizeof(array)/sizeof(array[0])). Didn't work.
I wrote a simple function:
int length(int array[]){
int i=0;
while(array[i]) i++;
return i;
}
Worked one minute, didn't work the next.
Someone please help! I'm using Xcode as an IDE
The length of an array is not part of the array in C, so when passing an array as a parameter to a function you should pass its length as a parameter too. Here's an example:
#define ARRLEN(a) (sizeof(a)/sizeof (a)[0]) /* a must be an array, not a pointer */
void printarray(int* a, int alen)
{
int i;
for (i = 0; i < alen; i++)
printf("%d\n", a[i]);
}
main()
{
int a[] = { 3, 4, 5 };
printarray(a, ARRLEN(a));
return 0;
}
However, if your array is defined in such a way as to always end with a sentinel that isn't normal data, then you can traverse the elements until you encounter the sentinel. e.g.,
void printstrings(char** a)
{
int i;
for (i = 0; a[i]; i++)
printf("%s\n", a[i]);
}
main()
{
char* a[] = { "This", "should", "work.", NULL };
printstrings(a);
return 0;
}
Passing an array into a function is the same as passing a pointer to the array.
So sizeof(array)/sizeof(array[0]) does not work.
You can define a global macro:
#define A_LEN(a) (sizeof(a)/sizeof(a[0]))
Try this
main()
{
int a[10] ;
printf("%d\n", sizeof(a)/sizeof(int) ) ;
}
output : 10
See Why doesn't sizeof properly report the size of an array when the array is a parameter to a function? from the comp.lang.c FAQ to understand why the sizeof method doesn't work. You probably should read the entire section on arrays.
Regarding your length function, your "simple" function can work only if your array happens to have the semantic that it is terminated with an element that has the value of 0. It will not work for an arbitrary array. When an array has decayed into a pointer in C, there is no way to recover the size of the array, and you must pass along the array length. (Even functions in the C standard library are not immune; gets does not take an argument that specifies the length of its destination buffer, and consequently it is notoriously unsafe. It is impossible for it to determine the size of the destination buffer, and it therefore cannot prevent buffer overflows.)
There are several methods to get the length of array inside a function (can be in the same file or in different source file)
pass the array length as a separate parameter.
make array length as global extern so that function can directly access global data
I'm a bit confused at the difference here, in C99:
int myfunc (int array[n], int n) { ... }
will not compile. As far as I know you must always put the reference to the array size first, so it has to be written:
int myfunc (int n, int array[n]) { ... }
But if you supply the static keyword, this works absolutely fine:
int myfunc (int array[static 1], int n) { ... }
This order if far preferable to me, as I'm used to having arrays come first in a function call, but why is this possible?
Edit: Realising that the third example isn't actually a VLA helps...
For reference, this was the piece of code I was looking at that led to the question:
int sum_array(int n, int m, int a[n][m])
{
int i, j, sum = 0;
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
sum += a[i][j];
return sum;
}
The reason why
int myfunc (int n, int array[n]) { ... }
is valid and
int myfunc (int array[n], int n) { ... }
is not is due to the lexical scoping rules of C. An identifier cannot be used before it has been introduced in the scope. There are a few exceptions to this rule but this one is not one of them.
EDIT: here is the relevant paragraph of the C Standard:
(C99, 6.2.1p7) "Any other identifier has scope that begins just after the completion of its declarator."
This rule also applies to parameters declaration at function prototype scope.
The reason for error has already been explained to you: you have to declare n before you can use it in other declarations.
However, it is worth noting that none of these declarations actually declare variable length arrays, as you seem to believe.
It is true that syntax with [n] was first allowed in C99 and that it is formally a VLA declaration, but nevertheless in the given context all of these declarations declare array as a parameter of int * type, just like it has always been in C89/90. The [n] part is not a hint of any kind. The fact that you can use [n] in this declaration is indeed a side-effect of VLA support, but this is where any relationship with VLA ends. That [n] is simply ignored.
A "hint" declaration requires keyword static inside the []. So, your declaration with [static 1] is equivalent to classic int array[1] declaration (meaning that 1 is ignored and the parameter has type int *) except that it gives the compiler a hint that at least 1 element must exist at the memory location pointed by array.
It's because arrays must be declared with a constant value so you cannot create an array using a variable size and therefore cannot pass an array with a variable size. Also if it is just a single-dimension array you don't need to pass a value in at all, that is the point of passing in the second parameter to tell you the length of your array.
To get this to work properly just write the function header like this:
int myfunc (int myArray[], int n) {...}
The order shouldn't matter, but you cannot have the size of an array you are passing be variable it must be a constant value.
If you are using GCC and are willing to use some of their extensions, you can accomplish what you wish right here:
int myFunc (int len; /* notice the semicolon!! */ int data[len], int len)
{
}
The documentation for this extension (Variable Length Arrays) is here.
Please note that this extension is NOT available in clang for some reason, I'm not quite sure why, though.
EDIT: Derp, scope, of course.
My question is; why do you need to do it at all? You're really getting a pointer anyway (you can't pass arrays to a function in C, they degrade to a pointer, regardless of the function's signature). It helps to let the caller know the expected size of the input, but beyond that it is useless. Since they are already passing the size, just use...
int myfunc(int arr[], size_t size) {
// ...
}
Or
int myfunc(int *arr, size_t size) {
// ...
}
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).