File 1.c
int a[10];
File main.c:
extern int *a;
int main()
{
printf("%d\n", a[0]);
return 0;
}
Gives me a segfault! What's going wrong?
Arrays decompose, or are implicitly converted to pointers when passed to a function as an argument, or when converted to an r-value on the right-hand-side of the assignment operator. So something like:
int array[10];
int* a = array; //implicit conversion to pointer to type int
void function(int* a);
function(array); //implicit conversion to pointer to type int
works just fine. But that does not mean that arrays themselves are pointers. So if you treat an array like a pointer as you've done, you're actually treating the array type as-if it was a pointer that held the address to an int object. Since your array is actually a sequence of int objects, and not pointers to int objects, you're actually trying to dereference to some memory location that isn't pointing to anywhere valid (i.e., the first slot in array is a numerical integer value like 0 which would be like dereferencing a NULL). So that is why you're segfaulting. Note that if you had done something like this:
int array[] = { 1, 2, 3, 4, 5};
int b = *array;
That still works, since array is again implicitly converted to a pointer to the memory block that is holding a sequence of integer values and is then dereferenced to get the value in the first sequence. But in your case, by declaring your array to the current code module as an externally defined pointer, and not an array, it will skip over the implicit conversion to a pointer that is normally done, and just use the array object as-if it were a pointer to an object itself, not an array of objects.
Well explained in the C FAQ. And there is a followup. The picture in the second link is worth a million bucks.
char a[] = "hello";
char *p = "world";
Short answer: use extern int a[].
A bit late, a duplicate of this problem was just entered (and closed). The answers here don't mention header files...
The problem would be caught at compile time if you put the declaration of array a in a header file, where it belongs, instead of putting it in the .c file. The header file should then be included into both .c files and the compiler can see that what you have declared is wrong.
Your header file would contain:
extern int myarray[];
You will get something like "error: conflicting types for a" if you declare a as a pointer instead.
Basically you'd need to write your main.c like this:
extern int a[];
int main()
{
printf("%d\n", a[0]);
return 0;
}
Check out the output of the following code.
File1.c
#include <stdio.h>
extern int* my_arr;
void my_print()
{
printf("%d", my_arr);
}
main.c
#include <stdio.h>
int my_arr[2] = {1,2};
extern void my_print();
void main()
{
my_print();
}
output
1
inside File1.c my_arr is a pointer variable that has the value of 1. meaning the 1st element of my_arr[] was assigned to it. Then if you use *my_arr to access memory location ox1, you get seg fault because you are not allowed to access ox01.
Why my_arr pointer was assigned 1 (the first element of my_arr[])?
Has to do with how assembler works. Read this article
Why your code can't access 0x01 ?
I know it has to do with the operating system not allowing some address space to be accessed by user code. Thats all I know. google it if you want more info.
Related
int func(int a[]);
int main()
{
int c = 21;
int *b;
b=&c;
printf("%d",b);
func(b);
return 0;
}
int func(int a[]){
printf("\n%d",(a));
printf("\n%d",*(a));
printf("\n%d",(a[0]));
printf("\n%d",(a[1]));
printf("\n%d",(a[2]));
}
this is something I'm trying to understand how these pointers work with arrays.
this is the output.
-680548828
-680548828
21
21
-680548828
32767
the first two 680548828 and the two 21s I understand. simply printing a would be the first element of array a[]. a[0] is like writing *a. what I dont get is why a[1] would have 680548828 in it. a[1] is the element in the array after the element where the pointer to 21 is stored(a[0])? sorry for the confusion please help. Thank you.
In your code
printf("%d",b);
invokes undefined behaviour, as you;re trying to print a pointer using %d. The correct way would be to use
%p format specifier
cast the argument to void *
The same logic is applicable to the called function also, remember, an array name decays to the pointer to teh first element, basically yields a pointer type, in most of the cases (including this specific usage).
That said, you are trying to access invalid memory in the called function. You passed a pointer to one int, and in the called function, you're trying to access memory outside the memory region, by saying a[1], a[2] etc. You cannot do that. It again invokes undefined behaviour.
The code below creates an array and a pointer that points to it. Then the program prints out the content of the two variables. The curious thing is that the memory addresses printed out are the same, even though they shouldn't. ptr should contain the address of array, not array itself. Can anybody explain this please?
#include <stdio.h>
int main() {
char array[] = "abcdefg";
char (*ptr)[] = &array;
printf("%p\n", array);
printf("%p\n", ptr);
}
For any array named array, array and &array has the same value - the address of the first element of the array. Just their types are different - array here has type char *, where are &array has type char(*)[].
For an example consider the array as char a[10];
when we are assigning to the pointer variable we assign as char *ptr=a
we can also assign like ptr=&a[0]; so the both statements are same the two will refer the starting address of the array
According to Pointers to arrays in C by Eli Bendersky:
Consider this code:
void test(int** p)
{
}
int main()
{
int arr[] = {30, 450, 14, 5};
test(&arr);
return 0;
}
gcc isn't very happy about it, and issues a warning: passing arg 1
of test from incompatible pointer type. C++ has stricter type
checking, so let's try running the same code through g++. As
expected, we get an error: cannot convert int (*)[4] to int** for
argument 1 to void test(int**).
So what's the problem here? What's wrong with the code above? Well,
everything. It's simply invalid, and it makes no sense. Some would
think it should work because this works:
void test(int* p)
{
}
int main()
{
int arr[] = {30, 450, 14, 5};
test(arr);
return 0;
}
But this one works specifically because the C compilers should follow
the C standard, which mandates that arrays "decay" into pointers when
used as lvalues. Thus, a pointer to the array's first element is
actually passed to test and everything works.
However, the first code snippet is different. While an array name may
decay into a pointer, the address of the array does not decay into a
pointer to a pointer. And why should it? What sense does it make to
treat an array so?
Pointers to pointers are sometimes passed to modify the pointers
(simple pointer arguments don't work here because C passes by value,
which would only allow to modify what's pointed, not the pointer
itself). Here's some imaginary code (won't compile):
void test(int** p)
{
*p = malloc ... /* retarget '*p' */
}
int main()
{
int arr[] = {30, 450, 14, 5};
int* ptr;
/* Fine!
** test will retarget ptr, and its new value
** will appear after this call.
*/
test(&ptr);
/* Makes no sense!
** You cannot retarget 'arr', since it's a
** constant label created by the compiler.
*/
test(&arr);
return 0;
}
Pointers to arrays
Note that the original code could be modified a little to make it
work:
void test(int (*p)[4])
{
(*p)[2] = 10;
}
int main()
{
int arr[] = {30, 450, 14, 5};
test(&arr);
printf("%d\n", arr[2]);
return 0;
}
What is that weird type test accepts now? Say hello to a "pointer to
array", one of the useless features of C. This is what the C FAQ has
to say about it:
2.12: How do I declare a pointer to an array?
Usually, you don't want to. When people speak casually of a pointer to
an array, they usually mean a pointer to its first element.
While the test function from the previous snippet compiles and works,
it isn't of much use, since it's much clearer to write:
void test(int* p)
{
p[2] = 10;
}
...
...
/* then call */
test(arr);
The main use of pointers as function arguments is to either avoid
passing whole structures by value, or to modify the object pointed by
the pointers. Both are irrelevant needs for pointers to array. Here's
a clarifying snippet:
int joe[] = {1, 2, 3, 4};
void test(int (*p)[4])
{
/* Fine: assign to an element through the
** pointer.
*/
(*p)[2] = 10;
/* Works, but won't be reflected in the
** caller since p was passed by value.
*/
p = &joe;
/* Error: arrays can't be assigned.
*/
*p = joe;
}
Arrays are not passed by value anyway, so a pointer to an array is
useless for this purpose. Neither can arrays be modified, so that
kills the second reason.
To answer the question, the reason for &array to be equal to array is because array is a "constant label created by the compiler," not a pointer variable. So it actually makes no sense to "dereference" array and the compiler happens to simply return the value of array itself whenever this happens.
array doesn't have an address, in the way that, say, ptr has an address. Because an array always points to the same memory location, there's no need for that memory location to be stored in some other memory location. There's no way to take array and get a temporary char** such that (*char)[0] == 'a'.
So &array has type char(*)[], and returns the location of the first char in the array. Likewise, array, when used in a pointer context (that is to say, pretty much everywhere, with a couple of exceptions), has the same effect as &array but with different type. This is known as "array decay".
More information at What is array decaying?.
I defined a global variable char buf[1024] in one file, and what's the correct may to declare it in other files? extern char buf[1024], extern char buf[], or extern char *buf? I found extern char buf[] works and extern char *buf doesn't, but would like to know more explanations.
You can use
extern char buf[];
but NOT
extern char *buf;
Because arrays are not pointers.
Reference: C FAQ
extern char buf[] and extern char buf[1024] both are ok.
In some case, the array is implemented by pointer, such as transfering arguments between two functions.
When you are making a variable as extern , you are indicating to the compiler that the symbol (address) of the variable would be found in another .o file - ( This is done during linking stage ) .
So while you are making a variable as extern , you just need to mention the name as it will give the information about address and size is not required
This is the old problem of arrays and pointers being interchangeable. Arrays and pointers are not interchangeable: they just happen to be most of the time, because most of the time you use an array name in an expression, where it decays into a pointer.
This specific case of defining as char array in one file and declaring as char pointer in the other file is thoroughly explained in Expert C Programming - Deep C Secrets; see chapter 4.
The declaration of an array gives you an array, and the declaration of a pointer gives you a pointer. The difference is that an array is an address - the address of the first element - and it is not a modifiable l-value, i.e., it can't be assigned to. On the other hand, a pointer is a variable holding an address.
Usually, the context is enough to tell whether you mean the address of a variable or the contents of the variable in an assignment. The statement
i = j;
Is saying to store the contents of j in the address of i. In compilers jargon, i is said to be an l-value, and j an r-value. The compiler has to generate code that writes the contents of the memory address of j in the memory address of i.
Consider these declarations:
char a[1024];
char *a;
What happens when you write a[i] = j;?
For the former case, the compiler will just pick the address of a's contents, which, in arrays, is the address of the first element; scale i, and sum it to the base address. Then it will write the contents of the address where j is stored into that address.
For the latter case, it is quite different: the compiler has to check the memory location where a is stored, load the contents of that memory location, use THAT as an address, and write the contents of j into that address.
If you declare a characters array like this in file1.c:
char a[] = "Hello";
And then define, in file2
extern char *a;
Then, executing a[0] = 'x'; in file2.c will crash: since you told the compiler that a is a pointer, it will check the address where a's value is stored. In reality, this address is holding the character code for 'H', but the compiler mistakenly interprets that as an address, and ends up generating code to write 'x' into the address 'H', which, if you're lucky, will crash your program with a segmentation violation.
Thus, this is a case where declaration and definition must match: if you declared it as an array, define it as an array; if you declared it as a pointer, define it as a pointer. You have to declare buf as a characters array in other files. Either of these forms is legal and equivalent:
extern char buf[1024];
or
extern char buf[];
Assignable global char variable. Make visible to all:
// shared_header.h
extern char current_mode[];
Define, instantiate and update:
// main.c
#include "shared_header.h"
char current_mode[160];
int main(int argc, char * argv [])
{
strcpy(current_mode, "MODE_CONFIGURE");
int a = randomNumber(102);
strcpy(current_mode, "MODE_EXECUTE");
int b = do_foo(a);
// other stuff
strcpy(current_mode, "MODE_TEARDOWN");
// close up shop
}
Read or update:
// foo.c
#include "shared_header.h"
int do_foo(int a)
{
printf("Current mode is %s", current_mode);
if (a > 100) {
strcpy(current_mode, "MODE_EXECUTE_SPECIAL_CASE");
printf("Switching to mode %s", current_mode);
}
// do useful things
}
When we pass an array as an argument we accept it as a pointer, that is:
func(array);//In main I invoke the function array of type int and size 5
void func(int *arr)
or
void fun(int arr[])//As we know arr[] gets converted int *arr
Here the base address gets stored in arr.
But when the passed array is accepted in this manner:
void func(int arr[5])//Works fine.
Does the memory get allocated for arr[5]?
If yes, then what happens to it?
If no, why isn't the memory allocated?
Does the memory gets allocated for arr[5]?
No, it doesn't.
If no,why memory is not allocated?
Because it's not necessary. The array, when passed to a function, always decays into a pointer. So, while arrays are not pointers and pointers are not arrays, in function arguments, the following pieces of code are equivalent:
T1 function(T2 *arg);
T1 function(T2 arg[]);
T1 function(T2 arg[N]);
void func(int *arr)
void func(int arr[])
void func(int arr[5])
are all equivalent in C.
C says a parameter of an array of type is adjusted to a pointer of type.
When you place an array size in a parameter declaration the number is totally ignored. In other words
void foo(int x[5]);
is exactly the same as
void foo(int *x);
Hope the following code/comments helps. When coding C the programmer must ensure that many items agree in various programs. This is both the fun and the bane of programming in C.
Note. Defining int arr[5] in a parameter list does NOT allocate storage for the data that is being passed. The declaration is valid and endorsed but only because it lets the compiler perform its type checking. Although, the compiler does allocate storage when a function is called that storage does not store YOUR data. You must allocate your data either through an explicit declaration (as in main in the following example) or you need to issue an malloc statement.
I ran the following code in Eclipse/Microsoft C compiler and NO statements were flagged with a warning or an error.
//In main invoke the functions all referring the same array of type int and size 5
void func1(int *arr)
{ // arr is a pointer to an int. The int can be the first element
// of an array or not. The compiler has no way to tell what the truth is.
}
void func2(int arr[])
{ // arr is a pointer to an array of integers, the compiler can check this
// by looking at the caller's code. It was no way to check if the number
// of entries in the array is correct.
}
void func3(int arr[5])
{ // arr is a pointer to an array of 5 integers. The compiler can
// check that it's length is 5, but if you choose to overrun the
// array then the compiler won't stop you. This is why func1 and func2
// will work with arr as a pointer to an array of ints.
}
void main()
{
int data_array[5] = {2,3,5,7,11};
func1(data_array);
func2(data_array);
func3(data_array);
}
Hope this helps, please ask for more info.
This might be a bit of a basic question, but what is the difference between writing char * [] and char **? For example, in main,I can have a char * argv[]. Alternatively I can use char ** argv. I assume there's got to be some kind of difference between the two notations.
Under the circumstances, there's no difference at all. If you try to use an array type as a function parameter, the compiler will "adjust" that to a pointer type instead (i.e., T a[x] as a function parameter means exactly the same thing as: T *a).
Under the right circumstances (i.e., not as a function parameter), there can be a difference between using array and pointer notation though. One common one is in an extern declaration. For example, let's assume we have one file that contains something like:
char a[20];
and we want to make that visible in another file. This will work:
extern char a[];
but this will not:
extern char *a;
If we make it an array of pointers instead:
char *a[20];
...the same remains true -- declaring an extern array works fine, but declaring an extern pointer does not:
extern char *a[]; // works
extern char **a; // doesn't work
Depends on context.
As a function parameter, they mean the same thing (to the compiler), but writing it char *argv[] might help make it obvious to programmers that the char** being passed points to the first element of an array of char*.
As a variable declaration, they mean different things. One is a pointer to a pointer, the other is an array of pointers, and the array is of unspecified size. So you can do:
char * foo[] = {0, 0, 0};
And get an array of 3 null pointers. Three char*s is a completely different thing from a pointer to a char*.
You can use cdecl.org to convert them to English:
char *argv[] = declare argv as array of pointer to char
char **argv = declare argv as pointer to pointer to char
I think this is a little bit more than syntactic sugar, it also offers a way to express semantic information about the (voluntary) contract implied by each type of declaration.
With char*[] you are saying that this is intended to be used as an array.
With char**, you are saying that you CAN use this as an array but that's not the way it's intended to be used.
As it was mentioned in the other answers, char*[] declares an array of pointers to char, char** declares a pointer to a pointer to char (which can be used as array).
One difference is that the array is constant, whereas the pointer is not.
Example:
int main()
{
char** ppc = NULL;
char* apc[] = {NULL};
ppc++;
apc++; /* this won't compile*/
return 0;
}
This really depends on the context of where the declarations occur.
Outside of a function parameter definition, the declaration
T a[];
declares a as an unknown-sized array of T; the array type is incomplete, so unless a is defined elsewhere (either in this translation unit or another translation unit that gets linked) then no storage is set aside for it (and you will probably get an "undefined reference" error if you attempt to link, although I think gcc's default behavior is to define the array with 1 element) . It cannot be used as an operand to the sizeof operator. It can be used as an operand of the & operator.
For example:
/**
* module1.c
*/
extern char *a[]; /* non-defining declaration of a */
void foo()
{
size_t i = 0;
for (i = 0; a[i] != NULL; i++)
printf("a[%lu] = %s\n", (unsigned long) i, a[i++]);
}
module1.c uses a non-defining declaration of a to introduce the name so that it can be used in the function foo, but since no size is specified, no storage is set aside for it in this translation unit. Most importantly, the expression a is not a pointer type; it is an incomplete array type. It will be converted to a pointer type in the call to printf by the usual rules.
/**
* module2.c
*/
char *a[] = {"foo", "bar", "bletch", "blurga", NULL}; /* defining declaration of a */
int main(void)
{
void foo();
foo();
return 0;
}
module2.c contains a defining declaration for a (the size of the array is computed from the number of elements in the initializer), which causes storage to be allocated for the array.
Style note: please don't ever write code like this.
In the context of a function parameter declaration, T a[] is synonymous with T *a; in both cases, a is a pointer type. This is only true in the context of a function parameter declaration.
As Paul said in the comment above, it's syntactic sugar. Both char* and char[] are the same data type. In memory, they will both contain the address of a char.
The array/index notation is equivalent to the pointer notation, both in declaration and in access, but sometimes much more intuitive. If you are creating an array of char pointers, you may want to write it one way or another to clarify your intention.
Edit: didn't consider the case Jerry mentioned in the other answer. Take a look at that.
char *ptr[2]={"good","bad"}; //Array of ptr to char
char **str; //Refer ptr to ptr to char
int i;
//str = &ptr[0]; //work
str = ptr;
for(i=0;i<2;i++) printf("%s %s\n",ptr[i],str[i]);
Its o/p same. Using that we can easily understand.