Access c variable as an array - c

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.

Related

Copying a string literal to an uint32_t array and accessing it

I pasted below code else where but it was suggested as a bad solution. The standard has this to say about memcpy:
"The memcpy function copies n characters from the object pointed to by s2 into the
object pointed to by s1. If copying takes place between objects that overlap, the behavior
is undefined."
and this about uint32_t:
"The typedef name uintN_t designates an unsigned integer type with width N and no
padding bits. Thus, uint24_t denotes such an unsigned integer type with a width of
exactly 24 bits."
Are there any alignment issues ? I have always been using this on linux and never encountered any bugs or such. I only use bitwise ops for access when i had to worry about the endianness for example receiving data over a link from another architecture. Kindly throw some light.
#include <stdio.h>
#include<string.h>
#include<stdint.h>
char* pointer = "HelloWorld!Hell!";
uint32_t arr[4];
unsigned char myArray[16];
int main(void) {
memcpy(arr, pointer, (size_t)16);
// Is this illegal ?
char *arr1 = (char *)arr;
for(int i = 0 ; i < 16; i++)
{
printf("arr[%d]=%c\n", i, arr1[i]);
}
}
The call to memcpy is fine. Where you have undefined behavior is here:
printf("%s\n", arr);
The %s format specifier expects a char * argument but you're passing a uint32_t *. Such an argument mismatch is undefined behavior. The two pointer types may have the same representation on your system, but that isn't necessarily true in general.
Even if the types matched, you would still have UB because arr isn't large enough to contain the string "HelloWorld!Hell!". This string (including the null terminating byte) is 17 bytes wide and so the null terminator isn't copied. Then printf reads past the end of the array which is UB.
As an example, I modified the list of variables as follows:
uint32_t x = 0x11223344;
uint32_t arr[4] = { 1, 2, 3, 4 };
uint32_t y = 0x55667788;
And got the following output:
HelloWorld!Hell!�wfU
As for this:
char *arr1 = (char *)arr;
This is legal because a pointer of one object type may be converted to a pointer to another object type. Also, because the destination type is char *, it is legal to dereference that pointer to access the underlying bytes of the original object.

Segmentation fault with typecast

When I run the following code it gives a segmentation fault:
#include <stdio.h>
int main() {
int i;
char char_array[5] = {'a', 'b', 'c', 'd', 'e'};
int int_array[5] = {1, 2, 3, 4, 5};
unsigned int hacky_nonpointer;
hacky_nonpointer = (unsigned int) char_array;
for(i=0; i < 5; i++) { // Iterate through the int array with the int_pointer.
printf("[hacky_nonpointer] points to %p, which contains the char '%c'\n",
hacky_nonpointer, *((char *) hacky_nonpointer));
hacky_nonpointer = hacky_nonpointer + sizeof(char);
}
hacky_nonpointer = (unsigned int) int_array;
for(i=0; i < 5; i++) { // Iterate through the int array with the int_pointer.
printf("[hacky_nonpointer] points to %p, which contains the integer %d\n",
hacky_nonpointer, *((int *) hacky_nonpointer));
hacky_nonpointer = hacky_nonpointer + sizeof(int);
}
}
I was actually trying to do a typecast example. How can I resolve the segmentation fault?
My guess is that you're on a 64-bit machine, where pointers are 64 bits. That will lead to big problems (and undefined behavior) when you do
hacky_nonpointer = (unsigned int) char_array;
as the type int is typically still only 32 bits.
Once you're experimented with this, then throw it all away, and forget all about as well! This is bad code doing bad things that no real program should ever do.
To expand on Some_programmer_dude’s answer a bit, the safe way to store a pointer in an integral type is
#include <stdint.h>
/* ... */
uintptr_t hacky_nonpointer = (uintptr_t)(void*)p;
To convert back,
const char c = *(char*)(void*)hacky_nonpointer;
On most real-world compilers, a direct cast from any pointer type to uintptr_t will work just fine. However, the standard technically only says that any pointer can be converted to void* and back, and that any void* can be converted to uintptr_t and back.
A round-trip conversion will get you an equivalent pointer back. (See the footnote for if you care about the language-lawyering details.) That is, you can convert p to a uintptr_t value and back, and you are guaranteed to get another pointer to the same object. You cannot safely increment the uintptr_t value and convert that back, but you could increment the pointer and convert the incremented pointer to uintptr_t and back. That is how you would safely do what you appear to want.
Converting to an integral type and adding 1 (or equivalently sizeof(char), which is guaranteed to be 1) is not guaranteed to give you anything meaningful. It’s possible to imagine esoteric implementations that will crash if you try to convert that value back to a pointer! However, on mainstream compilers, it will work.
If your compiler didn’t give you a warning about this code, you need to turn on more warnings. If it did, you shouldn’t ignore compiler warnings.
As the Dude said, though, you should never write code like that in the real world. No program should ever do anything like that or will ever need to.
Footnote
There is one extremely pedantic loophole to this: the Standard guarantees that a pointer converted to uintptr_t and back will compare equal to the original pointer, and it forbids two pointers to compare equal unless they can be used the same way. With one exception.
A pointer to the start of an array object might compare equal to a pointer one-past-the-end of a different array object. By my reading of the standard, an implementation that allowed a pointer resulting from a round-trip conversion of either kind of pointer (the beginning of an array object, or one past its end) to be used in only one of those ways could claim to be technically in compliance.
However, any real-world implementation would allow such a pointer to be used in both contexts. That the standard does not spell this out appears to be an oversight.

Subtracting two pointers giving unexpected result

#include <stdio.h>
int main() {
int *p = 100;
int *q = 92;
printf("%d\n", p - q); //prints 2
}
Shouldn't the output of above program be 8?
Instead I get 2.
Undefined behavior aside, this is the behavior that you get with pointer arithmetic: when it is legal to subtract pointers, their difference represents the number of data items between the pointers. In case of int which on your system uses four bytes per int, the difference between pointers that are eight-bytes apart is (8 / 4), which works out to 2.
Here is a version that has no undefined behavior:
int data[10];
int *p = &data[2];
int *q = &data[0];
// The difference between two pointers computed as pointer difference
ptrdiff_t pdiff = p - q;
intptr_t ip = (intptr_t)((void*)p);
intptr_t iq = (intptr_t)((void*)q);
// The difference between two pointers computed as integer difference
int idiff = ip - iq;
printf("%td %d\n", pdiff, idiff);
Demo.
This
int *p = 100;
int *q = 92;
is already invalid C. In C you cannot initialize pointers with arbitrary integer values. There's no implicit integer-to-pointer conversion in the language, aside from conversion from null-pointer constant 0. If you need to force a specific integer value into a pointer for some reason, you have to use an explicit cast (e.g. int *p = (int *) 100;).
Even if your code somehow compiles, its behavior in not defined by C language, which means that there's no "should be" answer here.
Your code is undefined behavior.
You cannot simply subtract two "arbitrary" pointers. Quoting C11, chapter §6.5.6/P9
When two pointers are subtracted, both shall point to elements of the same array object,
or one past the last element of the array object; the result is the difference of the
subscripts of the two array elements. The size of the result is implementation-defined,
and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. [....]
Also, as mentioned above, if you correctly subtract two pointers, the result would be of type ptrdiff_t and you should use %td to print the result.
That being said, the initialization
int *p = 100;
looks quite wrong itself !! To clarify, it does not store a value of 100 to the memory location pointed by (question: where does it point to?) p. It attempts to sets the pointer variable itself with an integer value of 100 which seems to be a constraint violation in itself.
According to the standard (N1570)
When two pointers are subtracted, both shall point to elements of
the same array object, or one past the last element of the array
object; the result is the difference of the subscripts of the two
array elements.
These are integer pointers, sizeof(int) is 4. Pointer arithmetic is done in units of the size of the thing pointed to. Therefore the "raw" difference in bytes is divided by 4. Also, the result is a ptrdiff_t so %d is unlikely to cut it.
But please note, what you are doing is technically undefined behaviour as Sourav points out. It works in the most common environments almost by accident. However, if p and q point into the same array, the behaviour is defined.
int a[100];
int *p = a + 23;
int *q = a + 25;
printf("0x%" PRIXPTR "\n", (uintptr_t)a); // some number
printf("0x%" PRIXPTR "\n", (uintptr_t)p); // some number + 92
printf("0x%" PRIXPTR "\n", (uintptr_t)q); // some number + 100
printf("%ld\n", q - p); // 2

Difference between int*a and char *a?

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.

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