Difference between int*a and char *a? - c

What is the difference between char *a and int *a as both work on Code Blocks for storing character pointer eg.
char *c, k = '$';
int *j;
j = &k;
printf("%c\n%p\n%c\n", k, j, *j);
c = &k;
printf("%c\n%p\n%c", k, c, *c);

Activate diagnostics and don't ignore them (-Wall -Wextra -pedantic-errors).
The compiler should tell you that you are doing something disallowed.
See here on coliru: http://coliru.stacked-crooked.com/a/31acb5b670254167
main.cpp:7:7: error: incompatible pointer types assigning to 'int *' from 'char *' [-Werror,-Wincompatible-pointer-types]
j = &k;
^ ~~
Answering your question, a char is an integer-type of lower rank than int (meaning potentially (and in practice nearly guaranteed) smaller size and value-range), and thus pointers to either are different types too.
Using a pointer of wrong type to access an object (with few exceptions) is UB.

Interpreting a character object as an integer
printf("%c\n%p\n%c\n", k, j, *j);
or storing the address of a char into an int pointer
j = &k;
is undefined behavour.
In your case you got the same result by chance. The code is incorrect and may as well print anything.

char *a
a is a pointer to something. That something is a char
int *b
b is a pointer to something. That something is an int
Both a and b are pointers, they only store memory addresses to other things, which is why it is possible (but definitely not reccommended; warning by default, error with -wError) to store the address of an int in a char *.
Dereferencing it is undefined behaviour and "anything could happen" which is why the warning/error is there in the first place.
It may work with your current machine and compiler. It isn't guaranteed to though, and literally anything could break it. Don't do it

In your case it will give the same value because sizeof(int)>size(char). If you really want to see the difference between char* and int*. Lets do this:
Assume: char is of 1 byte, int is 4 byte and addresses are also of 4 byte. To observe the difference between char* and int*.
int k=1024;
char* charptr= &k;
int* intptr=&k;
printf("%02x \n\n", *charptr); // this will simply print `00`
printf("%02x \n\n", *intptr); // this will simply print `400`
int i=0;
for(; i<4 ; i++)
printf("%02x ", *charptr++); // this will print `00 04 00 00`
NOTE: It is a little endian machine. First print displays the content of first byte only therefore we see 00 as output. Third print statements clears everything.
Hope this will help to understand the difference here.

What is the difference between a char pointer and an int pointer ?
Without considering what your code, the answer is simple Char pointer points to a memory address which holds a char value and an int pointer points to one with int value. This is and remains the difference between them. However, when you force the compiler to do something what they haven't been specified to, you either get an error or an unspecified behavior.
So, what's up with your code ?
That has already been explained well in answers but the basic thing is that char is stored as an ascii value and thus in your case an int pointer could point to a char.

Related

Why dereferencing after casting void pointer to pointer to char pointer makes problem?

I've learned pointer to pointer.
I am curious about dereferencing after casting "integer to pointer" (char*)(int) and "void pointer to pointer to char pointer." (char**)(void*)
Now there are some issues when I want to dereference to void pointer to pointer to char pointer.(char**)(void*)
I tried 2 cases.
integer to pointer (char*)(int)
#include <stdio.h>
int main()
{
int a = 10;
int b;
void* ptr = &a;
b = ptr;
printf("%d\n", *(unsigned int*)b);
printf("%d\n", *(void**)(b));
printf("%p\n", *(char**)(b));
return 0;
}
*(unsigned int*)b
*(void**)(b)
*(char**)(b)**
These three read 10 which is in address.
But the code below is problem. (Please watch ptr_speacial)
"void pointer to pointer to char pointer." (char**)(void*)
#include <stdio.h>
int main()
{
int arr[5] = { 1,2,3,4,5 };
char arr2[5] = { 1,2,3,4,5 };
void* ptr_arr;
void* ptr_arr2;
void* ptr_special;
ptr_arr = arr;
ptr_arr2 = arr2;
ptr_special = (char*)ptr_arr2 + 4;
printf("address : %p: value : %d\n", ptr_special, *(char**)ptr_special);
printf("%d\n", *(char**)ptr_arr);
return 0;
}
*(char**)ptr_special did not read 5 which is in address but -858993659
I'm not sure but I think this is overflow problem. What happend in this case? Please help me!
First of all, C has fairly lax rules when it comes to conversions between various pointer and integer types. If you add an explicit cast and thereby force a conversion, the code will compile in most cases. However, that doesn't necessarily mean that the code is correct. There are multiple forms of undefined behavior asociated with such wild conversions between different types. Alignment, type/address sizes, compatible types, pointer aliasing (What is the strict aliasing rule?) and so on. Lots of potential for bugs to consider.
There are many problems with this code. Specifically:
b = ptr; This is invalid C. You cannot assign an integer to a pointer without an explicit cast. "Pointer from integer/integer from pointer without a cast" issues. Yes "it compiles" but not without warnings. Code can compile with warnings and still be invalid C, see What must a C compiler do when it finds an error?.
b = (int)ptr; would still be problematic because the pointer type may not fit inside an int. You should be using uintptr_t rather than int for such cases. As a consequence of using the wrong type, your examples bug out and do not print the address when I run them on my computer, but rather some gibberish like 0022FE400000000A where it has managed to mess up pointer address + a value from the stack in the same 64 bit access. Which isn't guaranteed - it is undefined behavior - this was just what happened on one particular computer.
printf("%d\n", *(unsigned int*)b); is valid but questionable since it changes signedness of the actual data from int to unsigned int, then immediately tells printf to convert back to int by using the %d specifier. Doesn't make any sense.
Generally, you should printf pointers with %p or otherwise anything can happen.
*(void**)(b) is needlessly complicated, why not write (void*)b.
*(char**)(b) is questionable since it re-interprets the first byte of a into char which is potentially signed. You should be using uint8_t instead. More problematic yet is that the code states that the contents of b (that is: supposedly &a) is a char**, which you then convert to char*. It's an invalid pointer conversion since neither char* not char** are compatible types with int*. The compiler is free to do crazy things here.
*(char**)ptr_special is simply using the wrong pointer type. You convert from array to char* to void*. Then claim that the void* is actually a char** and try to de-reference it, so you get gibberish. Correct code is *(char*)ptr_special.
Summary:
Do not do wild pointer conversions between unrelated types unless you are absolutely sure what you are doing. The compiler may let all manner of crap through but that doesn't mean that the code is correct.
Take a look at this:
#include <stdio.h>
int main()
{
char arr2[] = { 1,2,3,4,5 };
char arr3[] = { 1,2,3,4,5 };
void* ptr_special2 = arr2 + 4;
void* ptr_special3 = arr3 + 4;
printf("address : %p: value : %d\n", ptr_special2, *(char**)ptr_special2);
printf("address : %p: value : %d\n", ptr_special2, *(char**)ptr_special3);
return 0;
}
output (may vary):
address : 0x7ffc5841755a: value : 50462981
address : 0x7ffc5841755a: value : 1074892805
Now try this:
char arr2[] = { 1,2,3,4,5,0,0,0 };
char arr3[] = { 1,2,3,4,5,1,0,0 };
output:
address : 0x7fffecb291fc: value : 5
address : 0x7fffecb291fc: value : 261
Try to work out what's happening before reading the ...
Explanation:
On my system, a "pointer to a pointer to a char" is 4 bytes long. So - when you take the address of the 5 in arr2, cast it to a char**, and dereference it - the system reads 4 bytes, starting at the 5.
In arr2, those 4 bytes are 5 0 0 0, which in a little-endian system is interpreted as 5.
In arr3, those 4 bytes are 5 1 0 0, which in a little-endian system is interpreted as 5 + 256 = 261.
In your code, the three bytes after the 5 are unknown. You don't know what the compiler has placed there (if anything). You are reading beyond the end of the array because you are trying to read 4 bytes (or whatever sizeof(char**) is on your system) from an array that only has 1 valid byte at that address.
This is undefined behaviour, which means the standard allows literally anything to happen - but typically, you could expect:
"random garbage" bytes
The beginning of the next local variable
An access violation
printf("address : %p: value : %d\n", ptr_special, *(char**)ptr_special);
You're passing char* as an argument so the program will take 8 bytes(or 4, depending on compiler setting) from ptr_special.
The memory beginning at arr2 will be something like this:
01 02 03 04 05 cc cc cc cc cc cc cc cc cc cc cc
It might be different from many reasons(optimization setting, etc) but important thing is that there are some values after arr2. When you use expression *(char**)ptr_special, the program will interpret that as 0xcccccccccccccc05(or 0xcccccc05) and pass to printf function.
Because you used %d as format specifier, function will print the value as 4 byte integer 0xcccccc05, which is -858993659.

Access c variable as an array

I've got moderately stuck, googling the right words can't got me to the right answer. Even worse, I've already done that but my own code example lost somewhere in the source code.
#include <stdio.h>
int main()
{
short x = 0xABCD;
char y[2] = { 0xAB, 0xCD };
printf("%x %x\n", y[0], y[1]);
printf("%x %x\n", (char *)&x[0], (char *)&x[1]);
}
Basically I need to access individual variable bytes via array by pointer arithmetic, without any calculations, just by type casting.
Put parentheses around your cast:
printf("%x %x\n", ((char *)&x)[0], ((char *)&x)[1]);
Note that endian-ness may change your expected result.
In the future, compile with -Wall to see what the warnings or errors are.
It's somewhat supported in C99. By a process known as type punning via union.
union {
short s;
char c[2];
} pun;
pun.s = 0xABCD;
pun.c[0] // reinterprets the representation of pun.s as char[2].
// And accesses the first byte.
Pointer casting (as long as it's to char*, to avoid strict aliasing violations) is also ok.
short x = 0xABCD;
char *c = (char*)&x;
If you're only bothered about getting the values, you can store the address of the source variable in a char * and increment and dereference the char pointer to print the values of each byte.
Quoting C11, chapter §6.3.2.3
[....] When a pointer to an object is converted to a pointer to a character type,
the result points to the lowest addressed byte of the object. Successive increments of the
result, up to the size of the object, yield pointers to the remaining bytes of the object.
Something like (consider pseudo-code, not tested)
#include <stdio.h>
int main(void)
{
int src = 0x12345678;
char * t = &src;
for (int i = 0; i < sizeof(src); i++)
printf("%x\t", t[i]);
return 0;
}
should do it.
That said, to elaborate on the accepted answer, the why part:
As per the operator precedence table, array indexing operator has higher precedence over the type-casting, so unless forced explicitly, in the expression
(char *)&x[0]
the type of x is not changed as expected. So, to enforce the meaningful usage of the type-casting, we need to enclose it into extra par of parenthesis.

How to access char array using an int pointer?

Hi how to access character array using integer point.
char arr[10] = {'1','2','3','4','5','6','7','8','9','10'};
int *ptr;
How i can print values of 'arr' using pointer ptr?
It is a little unclear what your goal is, but trying to print out a character array with an integer pointer is a bit like trying to get to the second step taking four-steps at a time. When you tell the compiler that you would like to reference a memory address with an integer pointer, the compiler knows that an integer is sizeof (int) bytes (generally 4-bytes on x86/x86_64). So attempting to access each element in a character array with an integer pointer and normal pointer arithmetic wouldn't work. (you would be advancing 4-bytes at a time).
However printing the character array though an integer pointer is possible if you use the integer pointer for the starting address of the array and advance the pointer by the number of characters in the array by casting back to char. While it is doubtful this is your goal, the plain statement of your question seems to suggest it. To accomplish this, you could:
#include <stdio.h>
int main (void)
{
char arr[] = {'1','2','3','4','5','6','7','8','9'};
int *ptr = (int *)arr;
unsigned int i;
for (i = 0; i < sizeof arr; i++)
printf (" %c", (*(char *)ptr + i));
putchar ('\n');
return 0;
}
Output
$ ./bin/char_array_int_ptr
1 2 3 4 5 6 7 8 9
Note: your original initialization of your array with a character '10' was invalid. If this was an assignment, it is likely intended to expose you to how pointer arithmetic is influenced by type and the ability to cast from and to type char (without violating strict aliasing rules)
If you are just after the integer values you can print out the characters as integers
for (i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i)
{
printf( "%d ", arr[i] );
}
Using a pointer of the wrong data type to access anything is undefined behavior, thus making it not something you want to do. If you want to cast a char to an integer, you can do that. If you want to print the integer value of a char, you can do that too.
But using a pointer type integer to access a char array is undefined behavior.

C Programming Simple Pointers

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.

How to cast an int's address of two variable to char pointer in C?

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);

Resources