I know there's tons of these and it's probably a simple question, but I can't seem to figure it out :(
char * char_buffer = (char *) malloc(64);
printf("%x\n", char_buffer);
memset(char_buffer,
0,
64);
printf("%x\n", char_buffer);
Output :
50000910
50000910
Why isn't char_buffer zero'd? Can someone explain what's happening?
You are confused about the difference between a pointer and space being pointed to.
Your code doesn't zero the pointer. It zeroes the space being pointed to. The memset function behaves that way. In fact you would not want to zero the pointer, as then it would no longer point to the memory you allocated.
Your printf statement attempts to print the pointer's value, which is the address of the space being pointed to. Not the contents of the space being pointed to.
Actually the printf statement causes undefined behaviour, because you mismatched format specifiers. Your compiler should have warned about this.
Here is some correct code:
printf("The buffer's address is %p\n", char_buffer);
printf("The buffer contains: %02X %02X %02X ...\n",
(unsigned char)char_buffer[0],
(unsigned char)char_buffer[1],
(unsigned char)char_buffer[2]);
To use the %X specifier you must pass non-negative values in, which is why the cast is necessary. You could declare the buffer as unsigned char * instead, in which case the cast would not be necessary.
You're printing the address of the buffer, not its contents. The contents are zero after the memset(). Just try:
printf("%d", char_buffer[0]);
and see the zero ;)
You're printing out the pointer, not the buffer values.
memset(p,v,n) writes the byte v to the byte pointed at by p and n-1 bytes after it. It doesn't touch the pointer p at all (it's passed in by value, how can it?)
To print out the buffer, you'd have to loop through it. I use something like this:
void printbuf(char *buf, int size)
{
int i = 0;
char b = 0;
for (i = 0; i < size; i++) {
if (i % 8 == 0) {
printf("\n%3d: ", i);
}
b = buf[i];
printf("%2hhX ", b);
}
}
Related
C programming newbie here...
I have a function which does some maths and stores the result in an output variable:
void myFunction(char* output) {
unsigned char myData[64]={0};
// Call to another function which fills the 'myData' array
compute(myData);
// Now let's format the result in our output variable
for (int n=0; n<64; n++) {
sprintf(output, "%s%02x", myData[n]);
}
}
The output char array is allocated by the caller in a variable called result:
void main(void) {
char* result = NULL;
result = malloc(129 * sizeof(unsigned char)); // twice the size of myData + 1 ending byte
myFunction(result);
// process result here
// (...)
free(result);
}
Problem is I always get some garbage stuff at the beginning of result, for instance:
���˶ang/String;8fb5ab60ed2b2c06fa43d[...]
Here the expected data starts at 8fb5ab60ed2b2c06fa43d. After doing some logs, I know that result already contains ���˶ang/String; before the sprintf() loop.
I don't understand how this can occur: isn't the malloc() function supposed to reserve memory for my variable? I guess this garbage comes from another memory area, which will eventually lead to some funky behavior...
That said, I've found a workaround just by adding a null ending byte at the 1st position of result, before calling the function:
result[0]='\0'; // initialisation
myFunction(result);
Now it works perfectly but I highly doubt that's good practice... Any advice?
Here's your problem:
for (int n=0; n<64; n++) {
sprintf(output, "%s%02x", myData[n]);
}
Your format specifier to sprintf expects a char * followed by an unsigned int. You're only passing in an unsigned char (which is converted to an int), so this character value is being interpreted as an address. Using the wrong format specifier to sprintf invokes undefined behavior.
It looks like you were attempting to append to output. The way to do that would be to only include the %02x format specifier, then on each loop iteration increment the pointer value output by 2 so that the next write happens in the correct place:
for (int n=0; n<64; n++, output+=2) {
sprintf(output, "%02x", myData[n]);
}
So, I just sat down and decided to write a memory allocator. I was tired, so I just threw something together. What I ended up with was this:
#include <stdio.h>
#include <stdlib.h>
#define BUFSIZE 1024
char buffer[BUFSIZE];
char *next = buffer;
void *alloc(int n){
if(next + n <= buffer + BUFSIZE){
next += n;
return (void *)(next - n);
}else{
return NULL;
}
}
void afree(void *c){
next = (char *)c;
}
int main(){
int *num = alloc(sizeof(int));
*num = 5643;
printf("%d: %d", *num, sizeof(int));
afree(num);
}
For some reason, this works. But I can not explain why it works. It may have to do with the fact that I am tired, but I really can not see why it works. So, this is what it should be doing, logically, and as I understand it:
It creates a char array with a pointer which points to the first element of the array.
When I call alloc with a value of 4 (which is the size of an int, as I have tested down below), it should set next to point to the fourth element of the array. It should then return a char pointer to the first 4 bytes of the array casted to a void pointer.
I then set that value to something greater than the max value of a char. C should realise that that isn't possible and should then truncate it to *num % sizeof(char).
I have one guess as to why this works: When the char pointer is casted to a void pointer and then gets turned into an integer it somehow changes the size of the pointer so that it is able to point to an integer. (I haven't only tried this memory allocator with integers, but with structures as well, and it seems to work with them as well).
Is this guess correct, or am I too tired to think?
EDIT:
EDIT 2: I think I've understood it. I realised that my phrasing from yesterday was quite bad. The thing which threw me off was the fact that the returned pointer actually points to a char, but I am still somehow able to store an integer value.
The allocator posted implements a mark and release allocation scheme:
alloc(size) returns a valid pointer if there is at least size unallocated bytes available in the arena. The available size is reduced accordingly. Note that this pointer can only be used to store bytes, as it is not properly aligned for anything else. Furthermore, from a strict interpretation of the C Standard, even if the pointer is properly aligned, using it as a pointer to any other type would violate the strict aliasing rule.
afree(ptr) resets the arena to the state is was before alloc() returned ptr. It would be a useful extension to make afree(NULL) reset the arena to its initial state.
Note that the main() function attempts to use the pointer returned by alloc(sizeof(int)) as a pointer to int. This invokes undefined behavior because there is no guarantee that buffer is properly aligned for this, and because of the violation of the strict aliasing rule.
Note also that the printf format printf("%d: %d", *num, sizeof(int)); is incorrect for the second argument. It should be printf("%d: %zd", *num, sizeof(int)); or printf("%d: %d", *num, (int)sizeof(int)); if the C runtime library is too old to support %zd.
Actually! I came up with a reason for the behaviour! This is what I was wondering, however, I wasn't too good at putting my thoughs into words yesterday (sorry). I modified my code to something like this:
#include <stdio.h>
#include <stdlib.h>
#define BUFSIZE 1024
char buffer[BUFSIZE];
char *next = buffer;
void *alloc(int n){
if(next + n <= buffer + BUFSIZE){
next += n;
return (void *)(next - n);
}else{
return NULL;
}
}
void afree(void *c){
next = (char *)c;
}
int main(){
int *num = alloc(sizeof(int));
*num = 346455;
printf("%d: %d\n", *num, (int)sizeof(int));
printf("%d, %d, %d, %d", *(next - 4), *(next - 3), *(next - 2), *(next - 1));
afree(num);
}
Now, the last printf produces "87, 73, 5, 0".
If you convert all the values into a big binary value you get this: 00000000 00000101 01001001 01010111. If you take that binary value and convert it to decimal you get the original value of *num, which is 346455. So, basically it separates the integer into 4 bytes and puts them into different elements of the array. I think this is implementation-defined and has to do with little endian and big endian. Is this correct? My first prediction was that it would truncate the integer and basically set the value to (integer value) % sizeof(char).
int *num = alloc(sizeof(int));
Says - 'here is a pointer (alloc) that points to some space, lets says it points to an integer (int*).'
The you say
*num = 5643;
Which says - set that integer to 5643.
Why wouldnt it work - given that alloc did in fact return a pointer to a block of good memory that can hold an integer
I want to print out things from given memory addresses.
Using this code, I can define a variable, define a pointer to it and print its contents using the pointer.
char buf[100];
void *p = buf;
strcpy(p, "Test string");
printf("Address: %X\n", &buf);
printf("Contents: %c\n", p);
What I want to do is to specify a certain memory address, and print out the contents of that block. I tried experimenting by incrementing and decremeting p, but it doesn't print out anything.
An interesting little problem. One that should occur to every programmer sooner or later, either out of curiosity or cussedness.
Essentially four parts.
Express the address you want as an integer of the appropriate size.
Cast the integer into a pointer to some type.
Dereference the pointer to get a value of that type.
Print the value.
[if desired, increment address and repeat.]
For simplicity I'll use an address of 0x1000 and integer contents.
int address = 0x1000;
int* pcontent = (int*)address;
int content = *pcontent;
printf ("Address %p: content %08x\n", pcontent, content);
Two points should be made.
This is undefined behaviour, but inevitable if you want to get a result.
The address I chose could be valid memory or could trigger a trap error or it could do just about anything. You'll have to experiment with different addresses to find out which.
[Many years ago I used this strategy to print out the entire contents of memory on a machine that had just 96KB of memory, which led to some interesting hacking possibilities. But I digress.]
You are using wrong specifier to print the address. Use %p and cast argument to void *.
printf("Address: %p\n", (void*)buf);
and to print string
printf("Contents: %s\n", p);
You have to define pointer p as
char *p = buf;
or to use casting then incrementing p. For example
p = ( char *)p + n;
For example
printf( "%s\n", ( char *)p + 5 );
You may not increment/decrement pointers of type void * because void in incomplete type.
Also the format specifiers in these calls
printf("Address: %X\n", &buf);
printf("Contents: %c\n", p);
are wrong.
If you want to print out a string you have to specify %s. if you wnat to print only one character then you should write
char *p = buf;
printf("Contents: %c\n", p[0]);
or
void *p = buf;
printf("Contents: %c\n", ( ( char *)p )[0]);
You are using %c instead use %s to print string printf("Contents: %s\n", p);
If we wanted to print random bytes from around memory, we would want to use:
char *p = buf;
printf("Address: %p\n", p);
printf("Contents: 0x%02x\n", *p);
Let's note though, that given a random address, dereferencing it can cause the application to fail. You can not assume that all of the memory space is valid.
You could try something like this:
void printMemory(void* mem, int bytes){
char* p = (char*) mem;
for(int i=0;i<bytes;i++){
printf("%x ",p[i] & 0xff);
if(i%8 == 7)
printf("\n");
}
}
This will print 8 bytes per row.
The program is available here: http://ideone.com/P1c15J
Here's briefly what it does:
Declares a string ptr. Converts this pointers address to a little-endian address and stores those bytes in a char[] adr. Prints this out.
Then concatenate the strings ptr and adr into badcode, print badcode.
The program actually works if you take out the last two lines (concatenation and print badcode). There is expected output.
For some reason there is no compilation error, no runtime error but also no output when I try to concatenate and print out the string.
EDIT: I know the output I'm expecting will be garbled because the bytes contained in adr don't map to ASCII characters. That's not a problem for me at the moment. I'm interesting in getting the address bytes in the string.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main(void) {
size_t i;
char badcode[500];
char const *ptr = "This string's little endian memory address is: ";
char adr[sizeof(void *) + 1];
uintptr_t ptrAddress = (uintptr_t)ptr;
printf("Pointer address is %p\n", ptr);
printf("Converting to 0x");
for(i = 0; i < sizeof(void *); ++i)
{
adr[i] = ptrAddress & 0xff;
printf("%2.2X", (unsigned int)(unsigned char)adr[i]);
ptrAddress >>= 8;
}
printf("\n");
snprintf(badcode, sizeof badcode, "%s%s", ptr, adr);
printf("\n%s", badcode);
return 0;
}
Trying to print unterminated string adr with
snprintf(badcode, sizeof badcode, "%s%s", ptr, adr);
As suggested by #adr, add before the printf()
adr[sizeof(void*)]=0;
OR (assuming sizeof(void*) is 4)
snprintf(badcode, sizeof badcode, "%s%hh02X%hh02X%hh02X%hh02X",
ptr, adr[0], adr[1], adr[2], adr[3]);
OP expects adr[4] to contain something like "\x12\x34\x56\x78", but what a[5] contains is something like '\x12', '\x34, '\x56, '\x78, junk. Since the last byte is not known to be '\0', UB results. When using snprintf(..., "%s", adr), the adr needs to be '\0' terminated.
Pointer Downcast
int* ptrInt;
char * ptrChar;
void* ptrVoid;
unsigned char indx;
int sample = 0x12345678;
ptrInt = &sample;
ptrVoid = (void *)(ptrInt);
ptrChar = (char *)(ptrVoid);
/*manipulating ptrChar */
for (indx = 0; indx < 4; indx++)
{
printf ("\n Value: %x \t Address: %p", *(ptrChar + indx), ( ptrChar + indx));
}
Output:
Value: 00000078 Address: 0022FF74
Value: 00000056 Address: 0022FF75
Value: 00000034 Address: 0022FF76
Value: 00000012 Address: 0022FF77
Question:
Why was sample divided into char sized data? And when pointer arithmetic is performed, how was it able to get its remaining value?
How this was possible?
Pointer Upcast
unsigned int * ptrUint;
void * ptrVoid;
unsigned char sample = 0x08;
ptrVoid = (void *)&sample;
ptrUint = (unsigned int *) ptrVoid;
printf(" \n &sample: %p \t ptrUint: %p ", &sample, ptrUint );
printf(" \n sample: %p \t *ptrUint: %p ", sample, *ptrUint );
Output:
&sample: 0022FF6F ptrUint: 0022FF6F
sample: 00000008 *ptrUint: 22FF6F08 <- Problem Point
Question:
Why is it that there is a garbage value in *ptrUint? Why is the garbage value similar
to ptrUint? Should malloc() or calloc() be used to avoid this garbage value? What kind of remedy would you suggest to remove the garbage value?
In the first example, you are using a char pointer so the data is going to be accessed a byte at a time. Memory is byte addressable, so when you add one to a pointer, you will access the next higher memory address. This is what is happening with the for loop. Using a byte pointer tells the compiler to access only the single byte, and rest of bits will show up as 0 when you are printing with %p.
In the second example, I think what is happening is that one byte is allocated for the sample byte, then the following 4 bytes were allocated to the ptrUint. So when you get the value starting at the memory address of sample and converting it to a 4 byte pointer, you just see the value in Sample plus the first 3 bytes of the ptrUint. If you cast this to a char pointer, and print, you would only see 8 in the output.
These aren't upcasts and downcasts, that would imply some kind of inheritance hierarchy.
In your first example you treat a pointer to an integer like if it was a pointer to char(s). Incrementing a pointer to int adds 4 to it, incrementing a pointer to char adds 1 to it (assuming 32 bit ints and 8 bit chars). Dereferencing them makes an int and a char, respectively. Hence the fragmentation into bytes.
In your second example you treat the unsigned char variable called sample as if it were a pointer to int, and dereference it. You are essentially reading garbage from the 0x08 memory address. I suppose you forgot a &. You are also passing a 1 byte char and a 4 byte int to the second printf, instead of 4+4 bytes, that messes up printf, reading 3 bytes more from the stack than you have given him. Which coincidentally is part of the ptrUint value given to the first call of printf. Using %c instead of %p should fix it.
The other answers have already explained why you're seeing what you're seeing.
I will add that your second example relies on undefined behaviour. It is not valid to dereference an int * that points to data that wasn't originally an int. i.e.:
char x = 5;
int *p = (int *)&x;
printf("%d\n", *p); // undefined behaviour