I'm a beginner at learning pointers. Here is my code. (Note: I'm still trying to get my head around pointers so my code won't be clean.)
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[]){
int a = 1;
char b = 's';
double c = 3.14;
int *ptra;
int *ptrb;
int *ptrc;
ptra = &a;
ptrb = &b;
ptrc = &c;
printf("I initialised int as %d and char as %c and double as %.2f\n", a, b, c);
printf("The address of A is %p and the contents of A is %d\n", ptra, *ptra);
printf("The address of B is %p and the contents of B is %c\n", ptrb, *ptrb);
printf("The address of C is %p and the contents of C is %.2f\n", ptrc, *ptrc);
I expected the following output:
I initialised int as 1 and char as s and double as 3.14
The address of A is 0xbf933094 and the contents of A is 1
The address of B is 0xbf933093 and the contents of B is s
The address of C is 0xbf933098 and the contents of C is 3.14
But instead I get this:
I initialised int as 1 and char as s and double as 3.14
The address of A is 0xbf933094 and the contents of A is 1
The address of B is 0xbf933093 and the contents of B is s
The address of C is 0xbf933098 and the contents of C is 427698.00000
Can someone help for the large number I got when printing the contents of C? Why don't I get 3.14? (The number is actually longer than that but it didn't fit into this textbox. :-))
You are declaring ptra, ptrb and ptrc as pointers to ints. But the type of a pointer is based on what it points to, so it really should be:
int *ptra;
char *ptrb;
double *ptrc;
In your specific case, your program is trying to interpret a double value through an int pointer. Since the sizes of these data types differ on your machine, some of the bits of the double get discarded and you end up with the strange number you're seeing.
This may not always happen the same way - the result of accessing something through the wrong type of pointer is not defined by the C language, but it still might compile. C programmers refer to this as undefined behaviour (a phrase you should really come to terms with if you want to learn C!).
There is also the fact that when you call printf, you need to give it variables of the type it expects from the format string. So if you give it a format string where the first placeholder is %.f, you must give it a first argument that's a double. If you don't, printf will also exhibit undefined behaviour and could do anything (the undefined behaviour may be strange output, crashing, or simply putting out the number you expect... until the worst possible moment).
Your pointers are all of type int. That is not correct. Replace those by
int *ptra;
char *ptrb;
double *ptrc;
Because your pointers are all int*. If you want it to dereference to a double, you need it to be double*. Your compiler should have warned you about incompatible pointer assignment.
You should declare pointers using the corresponding type.
int *ptra;
char *ptrb;
double *ptrc;
you need to change your pointer type to match your data type so the size will be set accordingly.
char *ptrb;
double *ptrc;
If I can just say a few words about typed pointers.
Pointers with a type (as opposed to void* pointers) know how many bytes to advance in memory. For example on 32 bit systems and integer pointer would typically advance four bytes in memory when iterating through an array containing integer values.
A char pointer (guaranteed by the C standard to be always 1 byte) would naturally advance 1 byte at a time.
Let me illustrate this with a small code snippet:
#include <stdio.h>
int main()
{
char array [] = "This is a char array.";
int* int_ptr;
char* char_ptr;
char_ptr = array; /* This is okay, we have a char array and we assign its address to a char pointer */
int_ptr = array; /* It will complain but let's go along with it */
printf("%p, %p, %p\n", array, char_ptr, int_ptr); /* They should all point to the same address in memory */
printf("%p\n", ++char_ptr); /* it will have advanced by one byte */
printf("%p\n", ++int_ptr); /* it will have advance by four bytes */
return 0;
}
I have the following output on my machine:
$ ./a.out
0xbf8b85d2, 0xbf8b85d2, 0xbf8b85d2
0xbf8b85d3
0xbf8b85d6
As you can see they have indeed advanced as we predicted. It is fairly obvious this can cause all sorts of problems when we start dereferencing our pointers and they don't match the underlying type.
Regarding void* pointers, arithmetic on them is illegal.
here the pointer ptrc is referring to the addressof varaible whose data type is integer but you are using it for double.
Related
I'm new to C and have a trouble understanding pointers. The part that I'm confused is about char * and int *.
For example, we can directly assign a pointer for char, like
char *c = "c"; and it doesn't make errors.
However, if I assign a pointer for int like I just did, for example int * a = 10;,
it makes errors. I need to make an additional space in memory to assign a pointer for int,
like int *b = malloc(sizeof(int)); *b = 20; free(b);...
Can anyone tell me why?
I think you're misunderstanding what a pointer is and what it means. In this case:
int* a = 10;
You're saying "create a pointer (to an int) and aim it at the literal memory location 0x0000000A (10).
That's not the same as this:
int n = 10;
int* a = &n;
Which is "create a pointer (to an int) and aim it at the memory location of n.
If you want to dynamically allocate this:
int* a = malloc(sizeof(int));
*a = 10;
Which translates to "create a pointer (to an int) and aim it at the block of memory just allocated, then assign to that location the value 10.
Normally you'd never allocate a single int, you'd allocate a bunch of them for an array, in which case you'd refer to it as a[0] through a[n-1] for an array of size n. In C *(x + y) is generally the same as x[y] or in other words *(x + 0) is either just *x or x[0].
In your example, you do not send c to the char 'c'. You used "c" which is a string-literal.
For string-literals it works as explained in https://stackoverflow.com/a/12795948/5280183.
In initialization the right-hand side (RHS) expression must be of or convertible to the type of the variable declared.
If you do
char *cp = ...
int *ip = ...
then what is in ... must be convertible to a pointer to a char or a pointer to an int. Also remember that a char is a single character.
Now, "abc" is special syntax in C - a string literal, for creating an array of (many) immutable characters. It has the type char [size] where size is the number of characters in the literal plus one for the terminating null character. So "c" has type char [2]. It is not char. An array in C is implicitly converted to pointer to the first element, having then the type "pointer to the element type". I.e. "c" of type char [2] in char *cp = "c"; is implicitly converted to type char *, which points to the first of the two characters c and \0 in the two-character array. It is also handily of type char * and now we have char *cp = (something that has type char * after conversions);.
As for int *, you're trying to pass an integer value to a pointer. It does not make sense.
A pointer holds an address. If you'd ask for the address of Sherlock Holmes, the answer would be 221 Baker Street. Now instead what you've done is "address of Sherlock Holmes is this photo I took of him in this morning".
The same incorrect code written for char * would be
char *cp = 'c'; // or more precisely `char *p = (char)'c';
and it would give you precisely the same error proving that char *cp and int *cp work alike.
Unfortunately C does not have int string literals nor literals for integer arrays, though from C99 onwards you could write:
int *ip = (int[]){ 5 };
or
const int *ip = (const int[]){ 5 };
Likewise you can always point a char * or int * to a single object of that type:
char a = 'c';
char *pa = &a;
int b = 42;
int *pb = &b;
now we can say that a and *pa designate the same char object a, and likewise b and *pb designate the same int object b. If you change *pa you will change a and vice versa; and likewise for b and *pb.
A string literal like "c" is actually an array expression (the type of "c" is "2-element array of char).
Unless it is the operand of the sizeof or & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "array of T" will be converted, or "decay" to an expression of type "pointer to T" and its value will be the address of the first element of the array.
So when you write
char *c = "c";
it’s roughly equivalent to writing
char string[] = "c";
char *c = &string[0];
You’re assigning a pointer to a pointer, so the compiler doesn’t complain.
However, when you write
int *a = 10;
you’re assigning an int value to a pointer and the types are not compatible, so the compiler complains. Pointers are not integers; they may have an integer representation, but that’s not guaranteed, and it won’t be the same size as int.
Are there differences between int pointer and char pointer in c?
short answer: NO
All pointers in C are created equal in the last decades. During some time there were pointers of different sizes, in some platforms like Windows, due to a thing called memory model.
Today the compiler sets the code to use 32-bit or 64 or any size pointers depending on the platform, but once set all pointers are equal.
What is not equal is the thing a pointer points to, and it is that you are confused about.
consider a void* pointer. malloc() allocates memory in C. It always return a void* pointer and you then cast it to anything you need
sizeof(void*) is the same as sizeof(int*). And is the same as sizeof(GiantStruct*) and in a 64-bit compiler is 8 bytes or 64 bits
what about char* c = "c"?
you must ask yourself what is "c". is is char[2]. And it is a string literal. Somewhere in memory the system will allocate an area of at least 2 bytes, put a 'c' and a zero there, since string literals are NULL terminated in C, take that address in put in the address allocated to your pointer c.
what about int* a = 10?
it is the same thing. It is somewhat ok until the operating system comes in. What is a? a is int* pointer to an int. And what is *a? an int. At which address? 10. Well, truth is the system will not let you access that address just because you set a pointer to point to it. In the '80s you could. Today there are very strong rules on this: you can only access memory allocated to your processes. Only. So the system aborts your program as soon as you try to access.
an example
if you write
int* a = malloc(300);
the system will allocate a 300-bytes area, take the area address and write it for you at the address allocated to a. When you write *a=3456 the system will write this value to the first sizeof(int) bytes at that address.
You can for sure write over all 300, but you must somewhat manipulate the pointer to point inside the area. Only inside that area.
In fact C language was designed just for that.
Let us write "c" to the end of that 300-byte area alocated to a:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char* c = "c";
int* a = (int*)malloc(300);
*a = 3456;
printf("Area content is %d\n", *a);
char* pToEnd = (char*)a + 298;
*(pToEnd) = 'c';
*(pToEnd + 1) = 0;
printf("At the end of the 300-byte area? [Should be 'c'] '%s'\n", pToEnd);
printf("The pointer c points to '%s'\n", c);
//*c = 'x'; // error: cancel program
c = pToEnd;
printf("The pointer c now points do the end of the 300-byte area:'%s'\n", c);
free(a);
return 0;
};
and see
Area content is 3456
At the end of the 300-byte area? [Should be 'c'] 'c'
The pointer c points to 'c'
The pointer c now points do the end of the 300-byte area:'c'
Also note that as soon as you try to write over c, the char pointer in your example, your program will also cancel. It is a read only area --- see the comment on line 14. But you can point c inside the area in the example and use it, since the pointer in itself is not constant.
And when you write c = pToEnd in the example above access to the string literal is lost forever. In some sense is a memory leak, but it is a static allocated area. The leak is not the area but the address.
Note also that free(a) at the end, even if being a int* will free all 300 bytes
The direct answer to your question, is that, C language is a strict typed language. And before the machine code is produced, a compiler checks for some possible errors. The types are different, and that is all that the compiler wants to know.
But from the bit-byte point of view, there are no difference, for C language, with the above two pointers.
Take a look at your code with online compiler
void main(){
int * a = 10; /* <= this presumably gives you an error. */
}
What I did is copy pasted your code that gives you the error. And online compiler had emitted a warning, not an error. Even more than that. Change the C standard to be of c17 and you still get a mere warning.
The note about assigning a string literal to a pointer had been discussed broadly at SO. It deserves a different topic.
To sum it up. For the C language there is no meaningful difference in the above two pointers. It is a user, who takes a responsibility to know a layout of a memory in his/her program. All in all, the language was designed as a high level tool that operates over linear memory.
If I have a pointer to an array of char*s, in other words, a char** named p1, what would I get if I do (char*)p1? I’m guessing there would be some loss of precision. What information would I lose, and what would p1 now be pointing to? Thanks!
If you had asked about converting an int ** to an int *, the answer would be different. Let’s consider that first, because I suspect it is more representative of the question you intended to ask, and the char * case is more complicated because there is a special purpose involved in that.
Suppose you have several int: int a, b, c, d;. You can make an array of pointers to them: int *p[] = { &a, &b, &c, &d };. You can also make a pointer to one of these pointers: int **q = &p[1];. Now q points to p[1], which contains the address of b.
When you write *q, the compiler knows q points to a pointer to an int, so it knows *q points to an int. If you write **q, the compiler, knowing that *q points to an int, will get *q from memory and use that as an address to get an int.
What happens if you convert q to an int * and try to use it, as in printf("%d\n", * (int *) q);? When you convert q to an int * you are (falsely) telling the compiler to treat it as a pointer to an int. Then, * (int *) q tells the compiler to go to that address and get an int.
This is invalid code—its behavior is not defined by the C standard. Specifically, it violates C 2018 6.5 7, which says that an object shall be accessed only by an lvalue expression that has a correct type—either a type compatible with that of the actual object or certain other cases, none of which apply here. At the place q points, there is a pointer to an int, but you tried to access it as if it were an int, and that is not allowed.
Now let’s consider the char ** to char * case. As before, you might take some char **q and convert it to char *. Now, you are telling the compiler to go to the place q points, where there is a pointer to a char, and to access that memory location as if there were a char there.
C has special rules for this case. You are allowed to examine the bytes that make up objects by accessing them through a char *. So, if you convert a char ** to char * and use it, as in * (char *) q, the result will be the first (lowest addressed) byte that makes up the pointer there. You can even look at the rest of the bytes, using code like this:
char *t = (char *) q;
printf("%d\n", t[0]);
printf("%d\n", t[1]);
printf("%d\n", t[2]);
printf("%d\n", t[3]);
This code will show you the decimal values for the first four bytes that make up the pointer to char that is at the location specified by q.
In summary, converting a char ** to char * will allow you to examine the bytes that represent a char *. However, in general, you should not convert pointers of one indirection level to pointers of another indirection level.
I find pointers make much more sense when I think of them as memory addresses rather than some abstract high level thing.
So a char** is a memory address which points to, a memory address which points to, a character.
0x0020 -> 0x0010 -> 0x0041 'A'
When you cast you change the interpretation of the data, not the actual data. So the char* is
0x0020 -> 0x0010 (unprintable)
This is almost certainly not useful. Interpreting this random data as a null terminated string would be potentially disastrous.
#include<stdio.h>
void main()
{
int *c=12345;
printf("dec:%d hex:%x", c ,&c); // (1)
}
The line (1) prints
dec:12345 hex:8af123
where 8af123 is obviously the address which is random and machine dependent.
When I put in
printf("dec:%d", *c); // (1)
it fails, obviously.
So my question is as per theoretical concept:
*c should holds the value 12345 but it is not. why?
And in this code:
#include<stdio.h>
void main()
{
char *c='a';
printf("address store in c:%d value point by c:%c address of c:%x", c,*c ,&c); //Focus line
}
Output is:
adderess store in c:9105699 value point by c:a address of c:8af564
why it is storing 'a' in *c instead in c?
I am using gcc compiler 4.4.3.
int *c=12345;
You just made a pointer that points to the (probably) invalid address 12345.
If you pass c (no *) to printf, you're passing the pointer itself. Therefore, printf simply sees the number 12345, and prints that. It has no way of knowing that that's supposed to be a pointer.
If you pass *c, to printf, you're dereferencing the pointer – you're passing the value at memory address 12345.
Since that's not a valid address, the dereference operation will crash (to be precise, will behave undefinededly) before it ever gets to printf.
So my question is as per theoretical concept *str hold the value 12345 but it is not. why?
int *c=12345;
is the same as:
int *c;
c=12345;
It is not the same as:
int *c;
*c=12345;
There is a semantical quirk in the C language here. The * belongs to the declaration, yet it only applies to that specific variable.
You could clarify the fact that * belongs to the declaration by putting it next to the data type:
int* c = 12345; // Don't format your declaration like this,
// see next example as to why
If you do, you will run into trouble when declaring multiple variables in the same statement:
int* a, b, c; // a is a pointer to int, b and c are plain int
// it is the same as:
int *a; int b; int c;
// and **not**
int *a; int *b; int *c;
So, you just have to learn that the * belongs to the declaration. There are no problems caused by this, because you cannot safely assign *c unless you first have assigned a valid address to c.
why it is storing 'a' in *c instead in c?
char *c='a';
printf("%d %c %x", c,*c ,&c); //Focus line
You are declaring a pointer to char that points to memory location 97 (The ascii value of a is 97).
You then try to print the pointer as a number (should print 97, but see below), the value of memory location 97 as a character (c is an invalid pointer at this stage, so the result is undefined, and the address of the pointer c (c is an aout variable located on the stack).
When I compile this code I get a
Warning: initialization makes pointer from integer without a cast
when assigning 97 to the character pointer c.
When I run this code in cygwin I get a Segmentation fault from the undefined behaviour.
I have an error in a C program. It says that %d requires int, but is reading int *. I used some mod10 functions before, to separate a 4 digit number. After manipulating each digit, with nothing more than division and other mod10's, I put the numbers back together as a 4 digit integer, and tell it to print it. With using %d in the printf line, i get an error back saying that %d is looking for an 'int', and it is finding an 'int *'. What exactly is an 'int *', and any ideas on what went wrong here?
An int * is a pointer to an int.
To get the value of a pointer to a variable use * in front of the variable name.
To get the address of a variable use & before it's name.
Example;
int c = 1, d= 0;
int *e = &c; // assign address of c to pointer e
d = *e; // assign value that c points to, to d
printf("%d",d); // print int value of d
printf("%d",*e); // same output as line above. print value c points to
Here is a little tutorial on pointers.
An int* is a pointer to an integer rather than an integer itself. C has the concept of pointers which are variables that can point to other variables, allowing you to do all sorts of wondrous things.
Without seeing your code, it's a little difficult to see what you've done wrong, but you can get a pointer by declaring it so:
int * pInt;
or by using the address-of operator:
doSomethingWith (&myInt);
An int* is a pointer to an integer, instead of an integer variable. This means that instead of holding some data, it holds a reference to a location in memory where some data is residing. If you want to access the data at the location that it references then you need to dereference the pointer.
To do this you do this:
int a = 100; //an integer variable
int* b= &a; //b is now the location of a in memory
cout << *b; //This dereferences b to the data in a, and prints 100
Hope this helps, any corrections anyone please let me know.
Show us (by editing it into your question) the line of code it's complaining about.
To answer your question, an int* is a pointer to an int. For example, given
int i;
int *p;
i and *p are of type int, and &i and p are of type int*.
Look up "pointers" in your C textbook.
Also, the comp.lang.c FAQ is an excellent resource; section 4 discusses pointers. (But it's mostly intended to answer questions you'll have after you've started to understand the concepts.)
int * is a pointer to an integer.
Please post the line of code that is flagged, the error message and the line that declares your variable.
I have the following code, but I'm getting incorrect output.
Can anybody tell me why output is 10 B only and why I'm not getting A in output??
#include<stdio.h>
#include<conio.h>
void main()
{
int *p;
char c,d;
int i;
clrscr();
p=&i;
*p=10;
(char *)p=&c;
*p=65;
(char *)p=&d;
*p=66;
printf("%d%c%c",i,c,d);
getch();
}
Your program invokes undefined behavior, so there's no correct or incorrect. Specifically:
*p = 65;
writes an integer into memory with only room for a char. C99 §6.5.3.2/4 (Address and indirection operations) states:
If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.84)
p has type pointer to int, so *p has type int. However, p is not a the address of a valid int object.
Also, I believe the cast on the left side of the assignment is illegal (GCC definitely thinks so).
I believe what's happening is that it's laid out (increasing addressess) like:
|i|i|i|i|d|c|p|p|p|p|
This represents the bytes each occupies. I'll walk through what I think is happening:
p = &i;
|i|i|i|i|d|c|00|00|00|00|
For simplicity, I assume the address of i is 0.
*p=10;
|10|0|0|0|d|c|00|00|00|00|
p=&c;
|10|0|0|0|d|c|05|00|00|00|
*p=65;
|i|i|i|i|d|65|00|00|00|00|
Note that modifying *p overwrites p.
p=&d;
|10|0|0|0|d|65|04|00|00|00|
*p=66;
|10|0|0|0|66|00|00|00|00|00|
So storing to d overwrites c with NULL. The above applies if your machine is little-endian, has 4-byte ints, and the stack grows upwards (towards lower addresses). The analysis is different if you have 2-byte ints, but the main conclusion still applies.
Returning void is also illegal, but that's unrelated.
The statement (char *)p=&c; doesn't magically turn p into a char * from that point on. In the next line, *p=65;, you're still putting an int into that location.
Ditto for (char *)p=&d; *p=66;. Now because you're inserting what's almost certainly two bytes into the single byte d, you're probably overwriting c with 0.
You may find that changing *p = 66 to *((char*)p) = 66 will give you what you want, the insertion of a single byte.
And, please, upgrade to gcc if possible. It costs exactly the same as Turbo C and is better in just about every way.
You want to use
p = (int *) &c;
but when you do
*p = 65
then the compiled program will put 65, as a 4-byte value (assuming your int is 4 byte) into the memory where c is residing. It will trash 3 more bytes... because c is only 1 byte, and you are putting 4 bytes of data into it... and I wonder whether some platform will complain as c is a char, and may not be at an int boundary...
You probably want to use
char *pChar = &c;
*pChar = 65;
If you want to experiment with putting a byte 65 into the integer i, you can use
pChar = (char *) &i;
*pChar = 65;
The (char *) is called casting -- making it a pointer to character.
I could not compile your program, it does not conform to ANSI standard. Here is fixed version and it prints "10AB":
#include<stdio.h>
int main()
{
int *p;
char *cp;
char c,d;
int i;
p=&i;
*p=10;
cp=&c;
*cp=65;
cp=&d;
*cp=66;
printf("%d%c%c\n",i,c,d);
}
Your main problem is that the whole thing is a hack. Don't do that. There is no reason to cast int or char back and forth like that. You can only expect trouble from the way you write your code.
Some hints:
the correct include file for standard
C is stdio.h
in C the expression (char*)p is not
an lvalue, meaning that you can't
assign to it. (this has good reasons)
Even if you would succeed to assign
the address of a char to an int
pointer this would generally a bad
idea. Not only because you will
eventually override memory that is
not "yours" but also because of
alignment problems. The best that can
happen to you in such a case is a
bus error, to tell you early that
you are on the wrong track
the return type of main is int
You are using the casting operator in wrong way. You an assiging an char * to int *. So you should cast that char * to allow the conversion. The correct code is as below:
int *p; char c,d; int i;
p=&i;
*p=10;
p=(int *)&c;
*p=65;
p=(int *)&d;
*p=66;
printf("%d%c%c",i,c,d);