Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
C++ implicitly converts char to int (a larger data type than char) in an expression, which means the following runs without a compile time error:
char a = 'a';
int b = a;
cout << b << endl;
// output
97
Why does the following then throw a compile time error:
char a = 'a';
char* str = &a;
int* ptr;
ptr = str;
Since pointers are of a fixed size (depending on 32/64 bit OS) irrespective of data type they are pointing to, please help me understand why this conversion is illegal.
"Since pointers are of a fixed size" the problem is not the size of the pointer, but the pointed type, a char is not an int, so a char * is not an int *
If you do after *str = <value> all is ok because you only change one byte, but *ptr = <value> will write into more than one byte with unexpected consequences etc
What you want to do is undefined behavior.
You start with a char and get a pointer to it. That's fine. For instance, the pointer could be 0x01. Then you say, actually that pointer to 1 byte, let's make it to a pointer to 4 bytes (32bits assumption for an int).
Obviously, that cannot work. Where are the other 3 bytes coming from?
Then, let's say that it does work. You get alignment issues, because the int should be aligned on 4bytes boundaries, and your pointer is not.
Hence lots and lots of issues what you want to do:
access to inexistent memory
bad memory access (alignement).
This cannot work.
When you assign a char to an int, you create a new variable, a new place with 4 bytes that can receive your data. Here, you don't create a new variable that can hold that data.
You had stated:
C++ implicitly typecasts char to int (a larger data type than char) in an expression, which means the following runs without a compile time error:
char a = 'a';
int b = a;
cout << b << endl;
Output:
97
Then you asked:
Why does the following then throw a compile time error:
char a = 'a';
char* str = &a;
int* ptr;
ptr = str;
In your first example, you declare a char variable named a and assign it the character 'a'. Then you declare an int variable named b and assign it the value of a. Then you call cout on b. This gives a value of 97 which is expected.
What is happening here is the compiler will implicitly cast the value of the char a to an integer. The reason you are seeing the value 97 is because this is the assigned ASCII code for the lower case a. The variable sizes here don't matter.
In your second example where you begin to ask about your compiler error is as follows:
You declare the same char variable as above and assign it the same character value a.
This time you create a pointer to a char and name it str and assign it to the address of a. str now points to a. Next you created a pointer to an int named ptr, then you try to assign str to ptr. Yes all pointers have the same size in memory, but what you are failing to understand here, is how pointer addressing works. Since you are not using new & delete respectively these pointers are on the stack. So on my machine I have ran this code:
#include <iostream>
int main() {
char a = 'a';
char* str = &a;
std::cout << &str << '\n'; // print str's address
int* ptr; // don't assign ptr to anything...
std::cout << &ptr << '\n'; // print ptr's address
}
On my machine the output is:
003BFC34 // this is the stack address of str
003BFC28 // this is the stack address of ptr
Yes both pointers themselves typically take up 4 bytes of memory on a 32bit machine. However, str is pointing to a char type of 1 byte, and ptr is pointing to a int type of 4 bytes on a 32bit machine.
So when you try to assign one pointer to another; this will only work when the pointer types are of the same type! Otherwise, you will either have a compiler error in your case or UB.
Your assumption in the first case is that the char became an int and that is not the case. What happens in your first case is it is taking the value that is represented by 1 byte and implicitly converts it to an integer type that takes 4 bytes and the integer representation of the lowercase a is the ASCII value of 97.
Therefore your 2nd case will not compile:
int main() {
char a = 'a';
char* str = &a;
int* ptr = str; // fails to compile.
return 0;
}
However, there is a way to convert pointers from one type to another
int main() {
char a = 'a';
char* str = &a;
int* ptr = (int*)(str); // C Style Cast - Will Compile!
int* ptr = reinterpret_cast<int*>( str ); // This will compile!
return 0;
}
When you assign int value to char variable and vice versa the compiler do the casting implictly.
But if you assign pointer of type int to address of char variable, it's illegal, because it's int pointer it should point to int variable.
The other direction is the same, char pointer should point to char integer.
The reason is because in memory char represented in one byte while int represented with four bytes.
It's important for memory allocating and freeing.
Related
What is the difference between int* i and int** i?
Pointer to an integer value
int* i
Pointer to a pointer to an integer value
int** i
(Ie, in the second case you will require two dereferrences to access the integer's value)
int* i : i is a pointer to a object of type int
int** i : i is a pointer to a pointer to a object of type int
int*** i : i is a pointer to a pointer to a pointer to object of type int
int**** i : i is a pointer to a pointer to a pointer to a pointer to object of type int
...
int* pi
pi is a pointer to an integer
int **ppi
ppi is a pointer to a pointer to an integer.
EDIT :
You need to read a good book on pointers. I recommend Pointers on C by Kenneth Reek.
Let's say you're a teacher and have to give notes to one of your students.
int note;
Well ... I meant the whole class
int *class_note; /* class_note[0]: note for Adam; class_note[1]: note for Brian; ... */
Well ... don't forget you have several classes
int **classes_notes; /* classes_notes[0][2]: note for Charles in class 0; ... */
And, you also teach at several institutions
int ***intitute_note; /* institute_note[1][1][1]: note for David in class 1 of institute 1 */
etc, etc ...
I don't think this is specific to opencv.
int *i is declaring a pointer to an int. So i stores a memory address, and C is expecting the contents of that memory address to contain an int.
int **i is declaring a pointer to... a pointer. To an int. So i contains an address, and at that memory address, C is expecting to see another pointer. That second memory address, then, is expected to hold an int.
Do note that, while you are declaring a pointer to an int, the actual int is not allocated. So it is valid to say int *i = 23, which is saying "I have a variable and I want it to point to memory address 23 which will contain an int." But if you tried to actually read or write to memory address 23, you would probably segfault, since your program doesn't "own" that chunk of RAM. *i = 100 would segfault. (The solution is to use malloc(). Or you can make it point to an existing variable, as in int j = 5; int *i = &j)
Imagine you have a few friends, one of them has to give you something (a treasure... :-)
Say john has the treasure
int treasure = 10000; // in USD, EUR or even better, in SO rep points
If you ask directly john
int john = treasure;
int you = john;
If you cannot join john, but gill knows how to contact him,
int john = treasure;
int *gill = &john;
int you = *gill;
If you cannot even join gill, but have to contact first jake who can contact gill
int john = treasure;
int *gill = &john;
int **jake = &gill;
int you = **jake;
Etc... Pointers are only indirections.
That was my last story for today before going to bed :-)
I deeply believe that a picture is worth a thousand words. Take the following example
// Finds the first integer "I" in the sequence of N integers pointed to by "A" .
// If an integer is found, the pointer pointed to by P is set to point to
// that integer.
void f(int N, int *A, int I, int **P) {
for(int i = 0; i < N; i++)
if(A[i] == I) {
// Set the pointer pointed to by P to point to the ith integer.
*P = &A[i];
return;
}
}
So in the above, A points to the first integer in the sequence of N integers. And P points to a pointer that the caller will have the pointer to the found integer stored in.
int Is[] = { 1, 2, 3 };
int *P;
f(3, &Is[0], 2, &P);
assert(*P == 2);
&P is used to pass the address of P to the function. This address has type int **, because it's the address of a pointer to int.
int* i is the address of a memory location of an integer
int** is the address of a memory location of an address of a memory location of an integer
int* i; // i is a pointer to integer. It can hold the address of a integer variable.
int** i; // i is a pointer to pointer to integer. It can hold address of a integer pointer variable.
Neither is a declaration. Declaration syntax does not allow () around the entire declaration. What are these () doing there? If this is supposed to be a part of function declaration, include the whole function declaration thing in your question, since in general case the actual meaning of a declaration might depend on that. (Not in this one though.)
As for the difference... There is one * in the first and there are two *s in the second. Does it help? Probably not. The first one declares ias a pointer to int. The second one declares i as a pointer to int *. Does this help? Probably not much either. Without a more specific question, it is hard to provide a more meaningful answer.
Provide more context, please. Or, if this is actually as specific as it can get, read your favorite C or C++ book about pointers. Such broad generic questions is not something you ask on the net.
Note that
int *i
is not fully interchangeable with
int i[]
This can be seen in that the following will compile:
int *i = new int[5];
while this will not:
int i[] = new int[5];
For the second, you have to give it a constructor list:
int i[] = {5,2,1,6,3};
You also get some checking with the [] form:
int *i = new int[5];
int *j = &(i[1]);
delete j;
compiles warning free, while:
int i[] = {0,1,2,3,4};
int j[] = {i[1]};
delete j;
will give the warnings:
warning C4156: deletion of an array expression without using the array form of 'delete'; array form substituted
warning C4154: deletion of an array expression; conversion to pointer supplied
Both of these last two examples will crash the application, but the second version (using the [] declaration type) will give a warning that you're shooting yourself in the foot.
(Win32 console C++ project, Visual studio 2010)
Textual substitution is useful here, but beware of using it blindly as it can mislead you (as in the advanced example below).
T var; // var has type T
T* var; // var has type "pointer to T"
This works no matter what T is:
int* var; // pointer to int
char* var; // pointer to char
double* var; // pointer to double
// advanced (and not pure textual substitution):
typedef int int3[3]; // confusing: int3 has type "array (of size 3) of ints"
// also known as "int[3]"
int3* var; // pointer to "array (of size 3) of ints"
// aka "pointer to int[3]"
int (*var)[3]; // same as above, note how the array type from the typedef
// gets "unwrapped" around the declaration, using parens
// because [] has higher precedence than *
// ("int* var[3];" is an array (size 3) of pointers to int)
This works when T is itself a pointer type:
typedef int* T; // T is a synonym for "pointer to int"
T* var; // pointer to T
// which means pointer to pointer to int
// same as:
int** var;
I am trying to pick up my C++; I have basic understanding of pointers and references; but when it comes to char pointer to array, it seems nothing works for me.
I have a small piece of codes here (omitted include and namespace statements), I have included my questions as comments below:
I have gone through at least 5 other questions on SO to try to understand it; but those answers didn't the answer I expected and to the extent that could help understand the actual issue there.
Could you kindly explain the problems I commented below with a bit of depth from the surface (so please don't dive into it directly)?
int main(){
// 1 this is a char pointer to a char;
char * c = new char;
*c ='A';
cout << c << endl; // this gives me memory address;
cout << *c << endl;// this gives me the value in the memory address;
// 2 this is a char array initialised to value "world";
char d[6] = "world";
cout << d[0] << endl; // this gives me the first element of char array;
// 3 this is char pointer to char array (or array of char pointers)?
char * str = new char[6];
for(int i=0;i<6;i++){ //
str[i]=d[i]; // are we assigning the memory address (not value) of respective elements here?
} // can I just do: *str = "world"; what's the difference between initialising with value
// and declaring the pointer and then assign value?
char * strr = "morning";
char b[6] = "hello";
cout << b << endl;
cout << (*str)[i] << endl; // why? error: subscripts requires array or pointer type
cout << str[1] << endl;
cout << (*strr)[1] << endl; // why? error: subscripts requires array or pointer type
}
// 1 this is a char pointer to a char;
Right.
// 2 this is a char array initialised to value "world";
Right, "world\0" is created by the compiler and is put in the read-only memory area of the program. Note that this is called a string literal. Then the string is copied over to the char array d.
// 3 this is char pointer to char array (or array of char pointers)?
That's a char pointer yes, a pointer to a single char.
// are we assigning the memory address (not value) of respective
elements here?
No, you're assigning the values of the elements. This is allowed because str[i] is the same as *(str + i) so you can use the same "array style" access with the pointer str. You're looping over the individual chars you have allocated with new and are assigning them the value of the chars in the char array d.
// why? error: subscripts requires array or pointer type
Because you already dereference str (which is pointing at the start of the 6 element char array) with * which gives you a char, then you try to use that char like an array with [1] which makes no sense. *str would give you 'w' (the first element). And str[1] would give you *(str + 1) which is 'o' (the second element), don't double up.
A small-big side note, string literals are of type const char[], not char[], they're placed in read only memory and thus they can not be altered by the program (don't write to them).
char * strr = "morning";
This is very very bad, it treats a const char[] as a char[], this has been deprecated in the standard for a while now and according to the current standard this is even illegal, yet compilers still allow it for some reason.
Because compilers allow this you could get some nasty situations like trying to modify the string literal:
char * strr = "morning";
strr[0] = 'w'; // change to "worning"
This will attempt to write to read-only memory, which is undefined behaviour and will probably/hopefully get you a segmentation fault. Long story short, use the appropriate type to have the compiler stop you before the code reaches runtime:
const char * strr = "morning";
side side note : don't forget to delete anything you allocated with new.
new learner ; something puzzle about pointer;
As I learn from books, before using the pointer it must be initialized , so we usually use like this
int a = 12;
int * p = &a;
so I understand why int* p = 12 is wrong ,because it has no address;
then I find something today while coding , That is from this :
char * months[12] = {"Jan", "Feb", "Mar", "April", "May" , "Jun", "Jul"
,"Aug","Sep","Oct","Nov","Dec"};
Then another usually used situation came to my mind , That is :
char *p = "string"; (this is ok , why int * a = 12 can't be allowed ?)
I am puzzled. when is it initialized and how ? and why int * a = 12 can't be auto initialized ? maybe something about the arrange of memory.
First off:
int a = 12;
int* p = &a;
This works because &a is a memory address.
int* p = 12;
This fails mostly because 12 is not a memory address. It's also true that 12, by itself, has no address, but this would be better reflected by a snippet like int* p = &12; (which wouldn't work, as you correctly noted).
An interesting property of pointers is that they are often used to designate the start of a list of values. For instance, take this array of integers:
int a[] = {1, 3, 7, 13};
It can trivially be turned into an integer pointer.
int* p = a; // magic!
The pointee is the first element of a, so *p == 1. Now, you can also do p[0] (which is 1, too), p[1] == 3, p[3] == 7, and p[4] == 13.
The reason char* foo = "bar" works is that "bar" is not a single value: it's a character array in disguise. Single characters are denoted by single quotes. As a matter of fact:
"bar"[0] == 'b'
"bar"[1] == 'a'
"bar"[2] == 'r'
The compiler has special support for string literals (quoted strings) that make it possible to assign them straight to pointers. For instance, char* foo = "bar" is valid.
A C99-compliant compiler also has support for array literals. For instance, int* p = (int [3]){1, 2, 3}; is valid. The character array and the int array will be given a global address, because the people who made C felt that it was a useful thing to do.
int* p = 12 is wrong because the assigned value may or may not belongs to memory address. You are forcing p to point at that location.
char *p = "string" is allowed because compiler already has set the space for the string and p is pointing to the first character of that string.
It comes down to types.
In both C and C++, the type of a plain integer literal like 12 is int. There is no implicit conversion from the type int to the type int*, which makes sense: a pointer and an integer are, conceptually, completely different things. So int *p = 12; is invalid.
In C, a plain string literal like "abc" is translated into a static array of chars (of size exactly sufficient to store abc plus a terminating null char). The type "array of chars" is implicitly convertible to the type char* (pointer to char) - arrays are said to decay into pointers. So the assignment char *p = "abc"; is valid.
But there's a catch: it's undefined behavior to modify that array (both in C and C++). That conversion is in fact deprecated (or even illegal) in C++, and you should use const char * instead.
In reality the gcc compiler will warn you about:
char* p = "hello";
This is because "hello" is now treated as an equivalent to const char*.
so this would be better:
const char* p = "hello";
But yes as other people have described, "hello" has an address which points to the start of a fixed sequence of characters.
int* p = 12 is wrong in the sense that it does something that is almost definitely not what you think it does. Assuming that your compiler doesn't complain that you are trying to implicitly cast an int into a int *, this is not illegal. What you did was, point p at memory location 12, which is almost definitely something you shouldn't be reading. The assignment is legal, but if you dereference that pointer you are in undefined behavior territory. If you are in user mode, then *(int*)12 is probably a segmentation fault.
Using C terminology, the difference between these two cases is that string literals exist, which are an array of char (and thus an lvalue, so you can take their address or point to them); but in C90 there are no other literals. 12 is an integer constant, not a literal. You can't do &(12), because the language says so. Brace-enclosed initializer lists are not values. Constants are rvalues; literals are lvalues.
In C++ the behaviour is the same, however C++ uses different terminology for the same thing. In C++, constants are all called "literals", however they are also all rvalues (except for string literals) so you cannot take their address.
C99 added array literals of other types.
The language has made an exception and allows string literals to be used to initialize char const*. Some compilers are less strict and allow string literals to be used to initialize char* as well.
Update, in response to comment by Pascal Cuoq
In C and C++, the following are valid ways to initialize variables using string literals:
char carr[] = "abc";
char carr[10] = "abc";
char const* cp = "abc";
The following are valid ways to initialize variables using integer literals in an initializer list:
int iarr[] = {1, 2, 3};
int iarr[10] = {1, 2, 3};
However, the following is not a valid way to initialize a variable using integer literals in an initializer list:
int const* ip = {1, 2, 3};
That's what I meant when I said the language has made an exception and allows string literals to be used to initialize char const*.
Many programmers are confused by the syntax of specifying a pointer.
int* p;
int *p;
int * p;
All of the above declare the same thing: a pointer, p, which either be NULL or the address of an integer-size storage unit in memory.
Thus
int * p = 12;
declares a pointer, p, and assigns it the value 12.
In C and C++ pointers are just variables with special meaning to the compiler such that you are allowed to use special syntax to access the memory location whose value they hold.
Think about this a different way for a moment.
Think of the number "90210". That could be your bank balance. It could be the number of hours since you were born.
Those are all simple "integer" interpretations of the number. If I tell you that it is a Zip Code - suddenly it describes a place. 90210 isn't Beverly Hills in California, it is the [postal] address of Beverly Hills in California.
Likewise, when you write
int * p = 12;
you are saying that "12" is the address of an integer in memory, and you're going to remember that fact in the pointer-variable p.
You could write
int * p = &12;
This will force the compiler to generate an integer storage unit in the program executable containing the native integer representation of 12, and then it will generate code which loads the address of that integer into the variable p.
char* p = "hello";
is very different.
12; // evaluates to an integer value of 12
"hello"; // evaluates to an integer value which specifies the location of the characters { 'h', 'e', 'l', 'l', 'o', 0 } in memory, with a pointer cast.
int i = 12; // legal
char h = 'h'; // legal
const char* p = "hello"; // legal
uintptr_t p = "hello"; // legal
The double-quotes in C and C++ have a special meaning, they evaluate to a pointer to the string contained in them, rather than evaluating to the string itself.
This is because
"The quick brown fox jumped over the lazy dog"
wouldn't fit into a CPU register (which are 32 or 64 bits depending on your machine). Instead, the text is written into the executable and the program instead loads the address of it (which will fit into a register). And this is what in C/C++ we call a pointer.
I have found on stackoverflow one good hint: always initialize declared pointer with NULL.
This will help understanding that newly created pointer cannot be used without further actions.
So the actions that should follow have to assign proper address to the pointer (initialize that pointer).
To do what was probably your intention with original code
int *p = 12;
you have to do for example:
int *p;
p = malloc(sizeof(p)); /* pointer p holds address of allocated memory */
*p = 12;
or another example:
int *p;
const int a = 12;
p = &a; /* pointer p holds address of variable a */
Why char *p = "string"; is correct was answered by others above. This is just another way of pointer initialization.
Also, similarly, in one of answers here on stackoverflow I have found really nice option for your case:
int *p = &(int){12};
int *ab = (int *)5656;
cout << *ab; //Here appcrash.
int *ab;
*ab = 5656;
cout << *ab; //These block crashes the app too.
But i can get the hex value of content of pointer if i write this:
int *ab = (int *)5656;
cout << ab; //Output is hex value of 5656.
So i want to ask: * is a operator that brings the contents of pointer(?) but why in this(these) example(s) app crashes?
And i can use that operator if i change code into this:
int a = 5656;
int *aptr = &a;
cout << *aptr; //No crash.
And why dereference operator(*) brings the only first character of a char:
char *cptr = "this is a test";
cout << *cptr; // Here output = 't'
cout << cptr; // Here output = 'this is a test'
int *ab = (int *)5656;
cout << *ab; //Here appcrash.
In this case, you are setting the pointer ab to point at the address 5656. Do you know what's at this address? No you don't. You are telling the compiler to trust you that there is an int there. Then, when you dereference the pointer with *ab, you obviously find that there isn't an int there and you get undefined behaviour. In this case, your program crashes.
int *ab;
*ab = 5656;
cout << *ab;
In this case, you have an uninitialised pointer ab which you then dereference to assign 5656 to the int it points at. Since it's uninitialised, dereferencing it gives you undefined behaviour. Think of it this way. You haven't put an addres in ab so you don't know where it points. You can't just dereference it and hope it points at an int.
int a = 5656;
int *aptr = &a;
cout << *aptr;
This is fine because you know you have an int object with value 5656 and you know that aptr contains the address of that int object. It's perfectly fine to dereference aptr.
const char *cptr = "this is a test";
cout << *cptr; // Here output = 't'
cout << cptr;
(Your code was using a deprecated conversion to char*, so I changed it to a const char*.)
The string literal "this is a test" gives you an array containing const chars. However, it then undergoes array-to-pointer conversion giving you a pointer to its first element. Since each element is a const char, the pointer you get is a const char*. You then store this pointer in cptr.
So cptr points at the first element of the string. Dereferencing that pointer gives you that first element, which is just the first character of the string. So you output t.
The I/O library has special overloads that take const char*s and treat it as pointing to a string of characters. If it didn't, cout << cptr would just print out the address in cptr. Instead, these special overloads will print out the null-terminated array of characters that cptr is assumed to point to.
I think it's worth noting that the application crashes you are observing are due to the fact that it is very unlikely that your process (i.e. program) owns the memory at the location you specify: 5656.
Modern operating systems disallow access to memory allocated by other processes.
Imagine what a headache it would be if that we're not the case: one program could modify the data associated with another one!
The "access violation" message is a helpful hint that you're accessing memory that your process does not own.
is a operator that brings the contents of pointer(?)
No. * is a operator that brings the contents of memory which pointer point to.
Here:
int *ab = (int *)5656;
cout << *ab; //Here appcrash.
Pointer ab contains 5656. *ab tries to access memory which pointer ab point to => *ab tries to access memory at address 5656. Your program is not allowed to access memory at address 5656 because it is not allocated or read-only => app crashes.
And i can use that operator if i change code into this:
int a = 5656; int *aptr = &a; cout << *aptr; //No crash.
Here you allocate and initialize memory: int a = 5656;
Here you write address of previously allocated memory to pointer: int *aptr = &a;
Here you access memory which was previously allocated: *aptr (memory contains 5656).
You have right to access it => app doesn't crash.
And why dereference operator(*) brings the only first character of a char
Because char is not string, char is character. When you dereference pointer to char, you get char.
C has no built-in type for string. That's why it's common to use pointer to memory containing string. This pointer usually points to a first character of string: char * - pointer to character
I have a rather simple question about arrays and pointer to arrays.
consider this code fragment..
int (*ptr)[3]; //A pointer to an array of 3 ints
int arr1[3] = {2,4,6,};
ptr = &arr1; //ptr now points to arr1
//3 different ways to express the same address
cout << &arr1 << "\t" << arr1 << "\t" << &arr1[0] << endl;
Now if:
&arr1 == arr1 == &arr1[0]..
why is this code not correct:
ptr = arr1;
or
ptr = &arr1[0];
This has been driving me crazy...so please any explanation would be appreciated. Also please not that this is not an homework question, just something I'm trying to get a grips on.
In
ptr = arr1;
arr1 is converted to an int*, so you're trying to assign from an incompatible pointer type. &arr1[0] is directly an int*, without conversion, so again incompatible.
&arr1 == arr1 == &arr1[0]
is wrong, since the entities have different types. They only point to the same address, so when printing out, they give the same result.
In most contexts, an expression with an array type is implicitly converted to a pointer to the first element of such array, as explained by 6.3.2.1p3:
Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type array of type is converted to an expression with type pointer to type that points
to the initial element of the array object and is not an lvalue.
Thus the right-hand side of your assignment
ptr = arr1;
is implicitly converted to an incompatible pointer type (int* vs. int (*)[3]), and can't be stored to the pointer variable without a cast.
This isn't really an exception to any rule, as you need to use the unary & operator with other types, too:
T val, *ptr;
ptr = &val;
Below programme will help you to better understand difference between
pointer_to_first_member_of_array, pointer_to_1D_array, pointer_to_2D_array.
Please carefully look at the programme, execute it and see output.
#include<stdio.h>
int priv_element = 88;
int array[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int next_element = 99;
main (int argc, char *argv[])
{
int *ptr_to_first_element = &array[0][0];
int (*ptr_to_1d_arry)[5] = &array[0];
int (*ptr_to_2d_arry)[2][5] = &array;
printf ("Print first num of first array of 2-Dim array: %d\n",
*ptr_to_first_element);
ptr_to_first_element += 5;
printf ("Print first num of second array of 2-Dim array: %d\n",
*ptr_to_first_element);
printf ("Print first num of first array of 2-Dim array: %d\n",
(*ptr_to_1d_arry)[0]);
ptr_to_1d_arry++;
printf ("Print first num of second array of 2-Dim array: %d\n",
(*ptr_to_1d_arry)[0]);
printf ("Print first num of first array of 2-Dim array: %d\n",
(*ptr_to_2d_arry)[0][0]);
ptr_to_2d_arry++;
printf
("Now you increased to point end of 2d-array space. So next to it is next_element on data-seg: %d\n",
(*ptr_to_2d_arry)[0][0]);
}
When you printed the various expressions, it showed you that their values were the same. However, they do not have the same types.
C and C++ include type features to reduce human mistakes and to make it easier to write complicated code. Suppose you had an address in some pointer p and C/C++ allowed you to do either:
float *f = p;
or:
int *i = p;
This would be a mistake, because, generally, whatever bits are in the memory at p do not represent both a useful int and a useful float. By enforcing rules about types, the language prevents a programmer from making a mistake here; the pointer p can only be assigned to another pointer of a compatible type, unless the programmer explicitly overrides the rules with a cast.
Similarly, your ptr is a pointer to an array of three int. At first, it might seem like your arr1 is also an array of three int, so you should be able to assign ptr = arr1;. This is wrong because ptr is merely a pointer, but arr1 is an entire array object. You cannot put an entire array into a pointer; you need to put a pointer to the array into the pointer. To get a pointer to the array, you use the & operator: ptr = &arr1;.
Another thing that is confusing here is that C/C++ includes an automatic shortcut: It converts an array to a pointer to the first element of the array. When arr1 appears in most contexts, it is changed automatically to &arr1[0]. There is not a huge philosophical reason for this; it is just a convenience for the ways we often use arrays. So ptr = arr1; would be equivalent to ptr = &arr1[0];, which is also not allowed. In this form, you can see that arr1 has become a pointer to an int, so you cannot assign it to a pointer to an array of int. Even though the pointer has the value you want, it is the wrong type.
When an array appears as the operand of & or sizeof or _Alignof, this automatic conversion does not occur. So &arr1 results in the address of the array.
A string literal that is used in an initialization such as char a[] = "abc"; is treated specially and is not automatically converted as described above.