Is this way of using indirect addressing correct? - c

I'm watching a college lecture about direct and indirect reference.
The professor just said that you can access a determined address by putting * and the address ahead of it. In the example he gave printf("%d", *7); will print the value in the memory address 7. That doesn't happen to be true, at least it didn't work at all for me.
For example, I had a variable num at address 0x28cc48 or 2673736. When I do *b = &num, I can access the variable's value with printf("%d", *b);, but If I try printf("%d", *2673736); or printf("%d", *0x28cc48); that won't work.
Here's the lecture, for those who want to check it: https://youtu.be/Rxvv9krECNw?t=8m45s
I don't know, I think his explanation is broken, but it may be that I'm missing the point, so I'm willing to know a bit more about this from the more experienced ones.

When you are using *7 in your code, the compiler has no real idea of what you are trying to de-reference. If you, on the other hand, tell it *(int*)7, it knows it has to de-reference it as an int.
In general, location 7 in memory would not even be accessible and it is a bad practice to hardcode addresses into your code. In the case of microcontrollers or embedded systems however, it might be used however.
When you say *b = &num, it matters whether you are doing it at declaration time, or after it, since int *b = # is very different from int *b; *b = #. In fact, the first usage is the same as int *b; b = #.
Here's some code to clarify the scenario that you are probably trying to get to:
#include <stdio.h>
int main() {
int num = 5;
int *a = &num;
int *b; b = &num;
printf("num = %d, &num = 0x%x", num, &num);
printf("a = 0x%x, *a = %d", a, *a);
printf("b = 0x%x, *b = %d", b, *b);
printf("*0xAAAAAAAA = %d", *(int*)0xAAAAAAAA); // Note: Replace 0xAAAAAAAA with whatever value you get for num from previous executions of this program
}
PS: It might be worth to take a look at Stanford's excellent resource on Pointers and Memory. http://cslibrary.stanford.edu/102/PointersAndMemory.pdf

If you want to access memory at a fixed address (common for example when accessing registers on a microcontroller), use an expression like this:
int tmp = *((int*)0x01234567);

Since a constant number does not really have a type, in order to use a constant number as an address, you have to tell the compiler the type of address by using a cast.
So if you have a particular memory address in low memory with certain types of constants you would need to specify the memory address with the cast in order for the compiler to know what type is the data at that memory location.
For instance you may have a set of unsigned shorts that are counters starting at a memory location of 8 with device names starting at a location of 0x700 so you could access them like so:
unsigned short iVal = *((unsigned short *) 8); // get unsigned short value at address 8
unsigned short jVal = *((unsigned short *) 10); // get unsigned short value at address 10
char *iName = (char *) 0x700; // get the address 0x700 into a char pointer
char *jName = (char *) 0x710; // get the address of 0x710 into a char pointer

Related

Pointer difference between int *val = otherVal and int val = otherVal

I am little confused and tried finding explanation but all "difference" questions asked are about type *name vs type* name which i know answer of.
I have code like this:
int a = 1;
printf("a = %d", a); // Prints 1
int *pt = a;
printf("pt = %d", pt); // Prints 1
*pt = 2; // Crash why? What am i pointing to here?
&pt = 2; // Not even compiling since
pt = 2; // Works
printf("pt = %d\n", pt); // Prints 2
printf("a = %d\n", a); // Prints 1
I know in order to change value of a i should have done int *pt = &a and then *pt = 2 and that is not my question.
My question is in this case, is using int *pt = a same as using int pt = a or is there any advantage of using it as pointer?
int a = 1;
...
int *pt = a;
Attempts to store the value 1 as the address held by pointer pt. Any dereference of pt is guaranteed to SegFault as address 1 is well down at the bottom of the system-reserved memory range -- which you have no ability to access, resulting in an access violation and SegFault.
What Is A Pointer?
A pointer is simply a normal variable that holds the address of something else as its value. In other words, a pointer points to the address where something else can be found. Where you normally think of a variable holding an immediate values, such as int a = 5;, a pointer would simply hold the address where 5 is stored in memory, e.g. int *b = &a;. It works the same way regardless what type of object the pointer points to. It is able to work that way because the type of the pointer controls the pointer arithmetic, e.g. with a char * pointer, pointer+1 point to the next byte, for an int * pointer (normal 4-byte integer), pointer+1 will point to the next int at an offset 4-bytes after pointer. (so a pointer, is just a pointer.... where arithmetic is automatically handled by the type)
So in your case:
int a = 1;
...
int *pt = &a;
Will assign the address where a is stored in memory to the pointer variable pt. You may then access the value at that address by dereferencing pt (e.g. *pt)
What you are doing is setting the address to which the pointer pt points to, to what a is currently holding (1 in your case). Since *a is most definitely not a valid and accessible address you will most likely get a segmentation fault when trying to dereference it. This is somewhat the same as if you are creating a null pointer by int *pt = 0 but instead of 0 you use whatever is in a.
Keep in mind that there is probably something funky going on with converting a signed int to an address which only makes the whole thing even worse.

Can we print the data just by using bare address in C?

I was wondering whether we can print data at a particular location just by using the bare address of that location in C language.
for eg, Here is the code I used :
#include<stdio.h>
int main(int argc, char** argv) {
int num = 10;
int *ptr;
ptr = &num;
//To output the address of the "num" variable
printf("Address: %p\n", ptr);
//Address is 0x7fff47808f50...
//Using that address to print the data at variable "num"
printf("Data: %d\n", *(0x7fff47808f50));
return 0;
}
But it is showing error. Maybe I've used the wrong syntax or maybe this is not the way to do it.Anyhow, please tell me the right way to do it.
You could (thought shouldn't) cast the integer to a pointer like so: (void *) 0x7fff47808f50.
The conversion has implementation-defined and undefined aspects, however, meaning your mileage will vary. The value will obviously change from compiler to compiler, perhaps even for different compilations, and byte order probably won't be the same as the way we conventionally write numbers, meaning you'll probably have to tinker quite a bit to get this working.
This is nonetheless demonstrable in practice, when that implementation-defined behaviour allows us to reproduce that behaviour, the following will be compliant:
unsigned long long ptr_as_integer = (unsigned long long) "hello world";
printf("%s", (void *) ptr_as_integer);
int value = 42;
unsigned long long value_ptr_as_integer = (unsigned long long) &value;
printf("%d", * (int *) value_ptr_as_integer);
There's also the uintptr_t type, which is designed specifically for this, but that's optional and so not guaranteed to exist...
It's fine to be curious; that's how we learn best... but please don't use this in practice! How often have you been taught not to use magic numbers?
You can use a char * to alias a pointer of another type to read individual bytes:
int i;
char *p = (char *)ptr;
for (i=0; i<sizeof(*ptr); i++) {
printf("p[%d]=%02hhx", i, p[i]);
}
Modify your code
#include<stdio.h>
int main(int argc, char** argv) {
int num = 10;
int *ptr;
ptr = &num;
//To output the address of the "num" variable
printf("Address: %p\n", ptr);
//Address is 0x7fff47808f50...
//Using that address to print the data at variable "num"
printf("Data: %d\n", *ptr);
return 0;
}
the answer to you question is YES.
BUT:
You must be 100% sure what address to use. For example in any kind of firmware you always have addresses of registers defined in manuals as regular numbers. and we use them like this
#define MY_REG_ADDR 0x12345ABC
int a = *((int*)(MY_REG_ADDR))
Modern OSes do address randomization so executable's virtual address sapce is changed every time you run your application so you CANNOT just use hardcoded address.
here is the output after i ran the app 4 times (modified code)
Address: 0x7ffc279af5ac
Data: 10
Address: 0x7ffc2d78021c
Data: 10
Address: 0x7fffb36ae32c
Data: 10
Address: 0x7ffca2c2a9ec
Data: 10
Every tine you change your code memory layout might change so variabl's address might also change

Casting char pointer to int pointer - buffer error 10

In this answer, the author discussed how it was possible to cast pointers in C. I wanted to try this out and constructed this code:
#include <stdio.h>
int main(void) {
char *c;
*c = 10;
int i = *(int*)(c);
printf("%d", i);
return 1;
}
This compiles (with a warning) and when I execute the binary it just outputs bus error: 10. I understand that a char is a smaller size than an int. I also understand from this post that I should expect this error. But I'd really appreciate if someone could clarify on what is going on here. In addition, I'd like to know if there is a correct way to cast the pointers and dereference the int pointer to get 10 (in this example). Thanks!
EDIT: To clarify my intent, if you are worried, I'm just trying to come up with a "working" example of pointer casting. This is just to show that this is allowed and might work in C.
c is uninitialized when you dereference it. That's undefined behaviour.
Likewise, even if c were initialized, your typecast of it to int * and then a dereference would get some number of extra bytes from memory, which is also undefined behaviour.
A working (safe) example that illustrates what you're trying:
int main(void)
{
int i = 10;
int *p = &i;
char c = *(char *)p;
printf("%d\n", c);
return 0;
}
This program will print 10 on a little-endian machine and 0 on a big-endian machine.
These lines of code are problematic. You are writing through a pointer that is uninitialized.
char *c;
*c = 10;
Change to something like this:
char * c = malloc (sizeof (char));
Then, the following line is invalid logic, and the compiler should at least warn you about this:
int i = *(int*)(c);
You are reading an int (probably 4 or 8 bytes) from a pointer that only has one byte of storage (sizeof (char)). You can't read an int worth of bytes from a char memory slot.
First of all your program has undefined behaviour because pointer c was not initialized.
As for the question then you may write simply
int i = *c;
printf("%d", i);
Integral types with rankes less than the rank of type int are promoted to type int in expressions.
I understand that a char is a smaller size than an int. I also understand from this post that I should expect this error. But I'd really appreciate if someone could clarify on what is going on here
Some architectures like SPARC and some MIPS requires strict alignment. Thus if you want to read or write for example a word, it has to be aligned on 4 bytes, e.g. its address is multiple of 4 or the CPU will raise an exception. Other architectures like x86 can handle unaligned access, but with performance cost.
Let's take your code, find all places where things go boom as well as the reason why, and do the minimum to fix them:
#include <stdio.h>
int main(void) {
char *c;
*c = 10;
The preceding line is Undefined Behavior (UB), because c does not point to at least one char-object. So, insert these two lines directly before:
char x;
c = &x;
Lets move on after that fix:
int i = *(int*)(c);
Now this line is bad too.
Let's make our life complicated by assuming you didn't mean the more reasonable implicit widening conversion; int i = c;:
If the implementation defines _Alignof(int) != 1, the cast invokes UB because x is potentially mis-aligned.
If the implementation defines sizeof(int) != 1, the dereferencing invokes UB, because we refer to memory which is not there.
Let's fix both possible issues by changing the lines defining x and assigning its address to c to this:
_Alignas(in) char x[sizeof(int)];
c = x;
Now, reading the dereferenced pointer causes UB, because we treat some memory as if it stored an object of type int, which is not true unless we copied one there from a valid int variable - treating both as buffers of characters - or we last stored an int there.
So, add a store before the read:
*(int*)c = 0;
Moving on...
printf("%d", i);
return 1;
}
To recap, the changed program:
#include <stdio.h>
int main(void) {
char *c;
_Alignas(in) char x[sizeof(int)];
c = x;
*c = 10;
*(int*)c = 0;
int i = *(int*)(c);
printf("%d", i);
return 1;
}
(Used the C11 standard for my fixes.)

Multiplying what's pointed to by pointers

Pointer1 points to 5.
Pointer2 points to 3.
I want to multiply 5*3, but I only have the pointers. How would I do this in C?
Also, what does uint32_t *pointer mean when:
pointer[2] = {1, 2};
I do not know what is so hard for the answerers to understand about this question. It is obviously about dereferencing pointers.
This is how you display the contents of the pointer that it is pointing to:
#include <stdio.h>
int main(void)
{
int num1 = 5;
int num2 = 3;
int* num1_ptr = &num1;
int* num2_ptr - &num2;
int sum = *num1_ptr * *num2_ptr;
printf("%d\n", sum);
return 0;
}
*num1_ptr and *num2_ptr takes your pointers and references what the contents of that memory address.
I can't answer the first half of your question without more information, but uint32_t* pointer is simply a pointer to an unsigned 32-bit integer value (unsigned int and uint32_t are usually equivalent types, depending on your compiler).
If I see a declaration that simply reads uint32_t* pointer without more information I'm going to assume it's a pointer to a single value, and that using the indexing operator [n] on such a pointer is basically overflowing the single-element-sized buffer. However if the pointer is assigned the result from an array or buffer function (e.g. malloc, calloc, etc) then using the indexing operator is fine, however I would prefer to see uint32_t pointer[] used as the declaration as it makes it much easier to determine the developer's intent.
uint32_t *pointer is just a pointer with garbage value unless you point it to something.
pointer[0] = 1;
pointer[1] = 2;
is only valid if you have earlier pointed it to some array of type uint32_t with atleast size two or to a block containing uint32_ts defined using malloc as follows:
uint32_t *pointer;
pointer = (uint32_t*)malloc(sizeof(int*SIZE); //SIZE > 2 here
or
uint32_t array[10];
pointer = & array[0]; // also, pointer = array; would also work.
int main(void)
{
int variableA = 5;
int variableB = 3;
int* ptr1 = &variableA; // Pointer1 points to 5.
int* ptr2 = &variableB; // Pointer2 points to 3.
int answer;
answer = (*ptr1) * (*ptr2); // I want to multiply 5*3, but I only have the pointers.
// Answer gets set to [value stored at ptr1(5)] MultipliedBy [value stored at ptr2(3)]
}
Your misconception is that pointers do not refer to values, such as 5 and 3.
pointers refer to variables, such as variableA and variableB; those variables have values which can be accessed and changed via the pointer.But the pointer only refers to the variable, not directly to the value behind it.

Understanding C: Pointers and Structs

I'm trying to better understand c, and I'm having a hard time understanding where I use the * and & characters. And just struct's in general. Here's a bit of code:
void word_not(lc3_word_t *R, lc3_word_t A) {
int *ptr;
*ptr = &R;
&ptr[0] = 1;
printf("this is R at spot 0: %d", ptr[0]);
}
lc3_word_t is a struct defined like this:
struct lc3_word_t__ {
BIT b15;
BIT b14;
BIT b13;
BIT b12;
BIT b11;
BIT b10;
BIT b9;
BIT b8;
BIT b7;
BIT b6;
BIT b5;
BIT b4;
BIT b3;
BIT b2;
BIT b1;
BIT b0;
};
This code doesn't do anything, it compiles but once I run it I get a "Segmentation fault" error. I'm just trying to understand how to read and write to a struct and using pointers. Thanks :)
New Code:
void word_not(lc3_word_t *R, lc3_word_t A) {
int* ptr;
ptr = &R;
ptr->b0 = 1;
printf("this is: %d", ptr->b0);
}
Here's a quick rundown of pointers (as I use them, at least):
int i;
int* p; //I declare pointers with the asterisk next to the type, not the name;
//it's not conventional, but int* seems like the full data type to me.
i = 17; //i now holds the value 17 (obviously)
p = &i; //p now holds the address of i (&x gives you the address of x)
*p = 3; //the thing pointed to by p (in our case, i) now holds the value 3
//the *x operator is sort of the reverse of the &x operator
printf("%i\n", i); //this will print 3, cause we changed the value of i (via *p)
And paired with structs:
typedef struct
{
unsigned char a;
unsigned char r;
unsigned char g;
unsigned char b;
} Color;
Color c;
Color* p;
p = &c; //just like the last code
p->g = 255; //set the 'g' member of the struct to 255
//this works because the compiler knows that Color* p points to a Color
//note that we don't use p[x] to get at the members - that's for arrays
And finally, with arrays:
int a[] = {1, 2, 7, 4};
int* p;
p = a; //note the lack of the & (address of) operator
//we don't need it, as arrays behave like pointers internally
//alternatively, "p = &a[0];" would have given the same result
p[2] = 3; //set that seven back to what it should be
//note the lack of the * (dereference) operator
//we don't need it, as the [] operator dereferences for us
//alternatively, we could have used "*(p+2) = 3;"
Hope this clears some things up - and don't hesitate to ask for more details if there's anything I've left out. Cheers!
I think you are looking for a general tutorial on C (of which there are many). Just check google. The following site has good info that will explain your questions better.
http://www.cplusplus.com/doc/tutorial/pointers/
http://www.cplusplus.com/doc/tutorial/structures/
They will help you with basic syntax and understanding what the operators are and how they work. Note that the site is C++ but the basics are the same in C.
First of all, your second line should be giving you some sort of warning about converting a pointer into an int. The third line I'm surprised compiles at all. Compile at your highest warning level, and heed the warnings.
The * does different things depending on whether it is in a declaration or an expression. In a declaration (like int *ptr or lc3_word_t *R) it just means "this is a pointer."
In an expression (like *ptr = &R) it means to dereference the pointer, which is basically to use the pointed-to value like a regular variable.
The & means "take the address of this." If something is not a pointer, you use it to turn it into a pointer. If something is already a pointer (like R or ptr in your function), you don't need to take the address of it again.
int *ptr;
*ptr = &R;
Here ptr is not initialized. It can point to whatever. Then you dereference it with * and assign it the address of R. That should not compile since &R is of type lc3_word_t** (pointer to pointer), while *ptr is of type int.
&ptr[0] = 1; is not legal either. Here you take the address of ptr[0] and try to assign it 1. This is also illegal since it is an rvalue, but you can think of it that you cannot change the location of the variable ptr[0] since what you're essentially trying to do is changing the address of ptr[0].
Let's step through the code.
First you declare a pointer to int: int *ptr. By the way I like to write it like this int* ptr (with * next to int instead of ptr) to remind myself that pointer is part of the type, i.e. the type of ptr is pointer to int.
Next you assign the value pointed to by ptr to the address of R. * dereferences the pointer (gets the value pointed to) and & gives the address. This is your problem. You've mixed up the types. Assigning the address of R (lc3_word_t**) to *ptr (int) won't work.
Next is &ptr[0] = 1;. This doesn't make a whole lot of sense either. &ptr[0] is the address of the first element of ptr (as an array). I'm guessing you want just the value at the first address, that is ptr[0] or *ptr.

Resources