Atmel Studio: How exacly do data breakpoints trigger? - embedded

OK folks. I set a Data Breakpoint in Atmel studio (With ICEmk2-JTag Debugger) and it won't get hit although the value at the address is changed. (I checked it with following breakpoints)
Why is this?
The whole purpose of Data breakpoints is to detect a change of the value at the address, or am I misunderstanding something?
To be more specific: I have a Pointer A that points to a value. But the pointer A is changed (not the value it points to!) by a bug I'm trying to hunt down.
So, I created a pointer B that points to the address where pointer A is stored and set a Data Breakpoint on Pointer B.
Here is the initialization:
#define lastCMDRingBufferSIZE 255
volatile uint8_t lastCMDRingbuffer[lastCMDRingBufferSIZE]; //
volatile uint8_t*lastCMDRingstartPtr = lastCMDRingbuffer; // This is PtrA
volatile uint32_t*ptrToPtr = &lastCMDRingstartPtr; // PtrB
Or another way to put it; Is a databreakpoint triggered if:
the content of the address is written by a array overflow?
the content of the address is interpreted as part of a larger data structure that is somehow written by a rogue pointer? (expl: a 64 bit pointer is dereferenced and written to, as a result a 32bit integer gets overwritten)
Your suspections and advice are highly appreciated :)

You are not addressing (pun not intended) this in the correct way. If the pointer A is being corrupted, the data breakpoint needs to be set on &A directly; creating a secondary pointer will not do anything useful unless you can set a conditional breakpoint of A != B.
Is a databreakpoint triggered if:
the content of the address is written by a array overflow? the content
of the address is interpreted as part of a larger data structure that
is somehow written by a rogue pointer? (expl: a 64 bit pointer is
dereferenced and written to, as a result a 32bit integer gets
overwritten)
It is triggered when the value at the breakpoint address changes - simple as that; the on-chip debug hardware has no concept of language constructs; the address you need to watch is therefore &A not A or B.
In the context of your actual code if lastCMDRingstartPtr is modified, ptrToPtr will not also change. Simply enter &lastCMDRingstartPtr as the address; then you will get a break when the value of lastCMDRingstartPtr changes.

The debug hardware I've used that supports break on data access aren't implemented like I think most people would expect them to be. The hardware doesn't monitor the memory at the address and issue a breakpoint if it changes, it monitors the read/write bus of the CPU and breaks if an access happens at the given address (or range of addresses) and of the correct width.
The end result is you can have some activities not be caught by the hardware. DMA accessing the memory is a big one that you simply cannot catch (unless your SRAM/DRAM interface has the ability to issue a fault like that). Also, if you're accessing the address in the mode which the debug hardware isn't configured for (i.e. doing byte writes when you're looking for word writes--which might be possible if you have a very naive memset/memcpy that does byte accesses)
My guess is you're doing some byte accesses on the array declared before your pointer and stomping on the pointer by overflowing the array. Even though you set up the word access hardware breakpoint on the pointer, it isn't being caught because you're doing byte accesses.

Related

Casting a memory location is disabled in ARC... How to get contents of the object then?

I used to be able to do this in Objective-c.
Now ARC disables this:
NSString *mice = #"dogs eat cats";
long dog = (long)mice;
NSString *appled = (NSString *)dog;
Am I missing something. If I know the address of my object how can I get the contents of it?
And it uses less memory (in your own comment on your question)
It uses exactly the same amount of memory: storing an n-bit pointer as an n-bit integer takes n-bits!
You should carefully review why you are doing this and whether your code will remain safe under ARC.
Pre-ARC you could "hide" a reference to an object and that object would stay around until you issued an explicit release().
Post-ARC there are bridge casts (multiple kinds exist) which enable you to explicitly take responsibility for object lifetime, and to later transfer the responsibility back.
To "hide" the reference as you do in your example therefore requires two bridge casts, one in each direction. Failure to do this correctly will result in objects being automatically released by ARC and memory faults/corruption when you attempt to use your recovered pointers.
The ARC documentation describes the various bridge casts and when to use them. However given your comment on memory use consider very carefully whether you should be doing this.
HTH
Addendum: Comment followup
You are misunderstanding how memory addresses, object lifetime, etc. work in (Objective-)C. I would strongly recommend you do not attempt to use any bridge casts until you have figured this out. Let's see if I can help you understand, with the help of an analogy or two.
Warning: Analogies always break down at some point, you should not push them too far and I'll try not to!
Let's look at your comment, it starts:
sizeof(long) = 8, sizeof(NSString)?-->"can't apply 'sizeof' to the class NSString".
You are correct that in Objective-C taking the sizeof of a class type is disallowed, but that is not what the issue is here. Look at the code in your question:
NSString *mice = #"dogs eat cats";
long dog = (long)mice;
Here you are not operating on a value of type NSString but on one of type NSString * - these two are very different.
Instead of considering NSString which is an object type in Objective-C think of a real world analogy: a building. In this analogy what is the equivalent of an object reference, such as NSString *? It is the address of the building.
Is a building address the same kind of thing as a building? No. Is it the same size as a building? No. You can write the address on a piece of paper and put it in your pocket. You can't put a building in your pocket (unless you are Gulliver ;-)). You can even put your piece of paper with an address on it inside a building, it fits easily.
What the address of a building does is enable to you locate the building, but it doesn't guarantee that there is a building at the address - it could have been demolished, and may have been replaced by a new building with a different purpose.
This is analogous to the address of an object, it enables you to locate the object, but is does not guarantee the object exists – it could have been destroyed, and its old location could now be part of some other object.
The comparison you were after is what is sizeof(long) compared to sizeof(NSString *). On current 64-bit Objective-C you'll find both of these result on 8.
Note: on the (rare) occasions you need to store an address in a integer you should not use the type long, rather you should use the type intptr_t which is a standard C integer type of the same size as an address. So your code should really have been:
NSString *mice = #"dogs eat cats";
intptr_t dog = (intptr_t)mice;
(That said, you probably shouldn't have written this code at all.)
Back to your comment, you continue:
But in it's place as an example, if I were to create a structure of 4 longs... the sizeof(struct4longs) = 32. Lets say you have a structure that takes 1mb of ram. Under ARC using their rules, to keep the reference, I would allocate 1mb to keep the reference to the 1mb... because the old way of referencing(keeping only addresses) is no longer allowed-->NSString *appled = (NSString *)dog;
No, no, no. An address is the same size regardless of what it references.
In our analogy of buildings the addresses "330 5th Ave, New York" and "350 5th Ave, New York" are exactly the same size. The first is a Panera Bread cafe, the second is the Empire State Building – the buildings are not the same size!
Converting an object address to an integer does not save any space at all.
The difference between pre-ARC and post-ARC
Sticking with our analogy: In pre-ARC times buildings were built (alloc/init, new, etc.), marked as in use (retain), marked as no longer required (release), and eventually demolished (object destruction) manually.
A building could be left empty and unused and it just stood there, using up space, unless the builder (programmer) came along and demolished it (the programmer matches a release for every retain).
You could write the address of a building in your address book (store its address in a pointer-typed variable such as NSString *), it did not have any effect on the lifetime of the building.
You could keep an obscured copy of the building address, say write it in code and put it in your calendar (the equivalent of you placing an object address in an integer typed variable), it still had no effect on the lifetime of the building.
So in the pre-ARC days your scheme "worked" – in that you could hide and recover object addresses – but it had no real purpose, it didn't save any space, just made your code harder to understand and more error prone. You had to use manual calls (retain, release) to control the lifetime of your objects.
The post-ARC world changes all this.
In the post-ARC world building demolition was taken over by an automatic robotic system, buildings no longer in use are demolished. No action required by humans (programmers).
So how does the robotic system know when a building can be demolished?
Coloured paper! (I do not joke, but remember this is an analogy)
The rule is simple: write down the address of a building on a piece of yellow paper and the robot demolition crew will not demolish the building.
Get an eraser and rub out the buildings name from every piece of yellow paper it is on and the robot crew will, at some time of their choosing, move in and demolish it.
Same thing happens if you throw away or burn the piece of yellow paper. Only yellow paper owned by someone is considered by the robot demolition crew. (This includes yellow paper found inside buildings provided the address of that building is written down on a piece of yellow paper, and if that piece of yellow paper is in a building then that building's address is written on another piece of yellow paper... etc., and provided at some point there is a piece of yellow paper not in a building which starts the chain off.)
Write the address on a piece of white paper and the robots just ignore the piece of paper. Only owned yellow paper prevents the building being destroyed.
What your old pre-ARC code does in the the new post-ARC world is transfer the address of a building from a yellow piece of paper to a white piece, and then throws aways the yellow piece. Not good when there is an eager robot demolition crew looking to demolish buildings out there.
Later you try to copy the address from your white piece of paper back onto a yellow piece in the hope that the robots haven't found the building yet... hopes get dashed, that's life. Left something important in the building? A priceless work of art maybe left hanging on the wall? Tough.
Enough analogy, back to Objective-C:
The yellow pieces of paper are technically called strong references, a variable of object type (e.g. NSString *) in the post-ARC world is (usually, the few exceptions can be ignored at this point) implicitly marked as strong (e.g. __strong NSString *).
The white pieces of paper are all non-object pointer typed variables (e.g. long, intptr_t, and even int * etc.) and object pointer typed variables explicitly marked as __unsafe_unretained – that name should tell you everything, storing an address only in any such variable is unsafe as the object will not be retained, the automatic object reclamation will destroy it.
Conclusion:
Do not do what you were doing in the pre-ARC days.
In those days it saved no memory and had no useful purpose, however it wasn't unsafe.
In the post-ARC days it not only has no useful purpose, it is unsafe.
Just store your addresses as addresses.
You might wonder why bridging casts exist. Well there are special cases where they are needed, they are not for general use. When, and if, you get to those cases you'll read about them and how to use them safely.
I hope the above helps you sort this out!
You need to cast it to void * first:
NSString *appled = (__bridge NSString *)((void *)dog);
Updated. Because of down votes on this post I need to add a warning: Obj-C is flexible enough to let you fix such kind of compiler errors, but if you tying to do so - you need to be completely sure what you are doing and why.
Storing object pointer in non-object type will act like __unsafe_unretained variable.
__unsafe_unretained specifies a reference that does not keep the referenced object alive and is not set to nil when there are no strong
references to the object. If the object it references is deallocated,
the pointer is left dangling. (source)
So even if you need to make such type casts (for any reason), and you want your object to be valid - you need to ensure that this object has at least one strong reference.
And in case if you don't want to keep strong references to original object, you can count references by yourself using __bridge_retained and __bridge_transfer
NSString *mice = #"dogs eat cats";
long dog = (long)(__bridge_retained CFTypeRef)mice;
// here original mice object has retain count +1
NSString *appled = (__bridge_transfer NSString *)((void *)dog);
// here __bridge_transfer decreased previously gained retain count by 1

Difference between a constant and variable member in compiled or interpreted code

For a while now I have been a little confused about the role of constant members within a language, such as Java or C. I understand that at the source code level, they prevent certain critical members from being mutated and changed, but when compiled or interpreted, is there any difference between them and variable members at all or are they all just pointers to memory addresses?
I thought that perhaps the compiler/interpreter has to implement something special to allow a variable to be mutable, something it wouldn't have to when handling a constant member (perhaps making execution faster or making it use less memory?), is this true or am I completely up the wrong tree?
The const variable and the variable are not stored in the same place once your code is executed. The constant values will go in the flash memory with your program. The variables will go in the flash too but will then be copied in the ram to be modified as your program runs. Making a variable const makes your computer save time and space by not pushing everything in the ram. When you need to modify it, you will push it into the Ram anyway, but most of the time const variables will not be modified.
This is in addition to the software fact that you might want to prevent your code to modify a value by mistake.

Local variable being stored over different function calls. weird

I'm bewildered by whats happening. It's more of a trick question I don't know the answer to.
I have the following function inside my main.m of an Objective-C program.
int incrementCounter(){
int counter;
counter+=2;
return counter;
}
and inside my main.m
NSLog(#"Counter: %d",incrementCounter());
NSLog(#"Counter: %d",incrementCounter());
NSLog(#"Counter: %d",incrementCounter());
The weird thing is one mac book(don't know the Xcode version ) when I executed this the output was:
2013-05-28 19:16:27.131 SOQ[4923:707] Counter: 1
2013-05-28 19:16:27.132 SOQ[4923:707] Counter: 3
2013-05-28 19:16:27.132 SOQ[4923:707] Counter: 5
My questions here:
1. How did counter get initialized to 1? (when i use static it get initialized to zero)
2. How is the value being stored over successive method calls?
3. When I check for the memory location of this variable for different executions of the program it remains the same. How does that happen?
And when I executed the same piece of code in another mac(lion Xcode 4.2.1) it gives the following output:
2013-05-28 19:16:27.131 SOQ[4923:707] Counter: 32769
2013-05-28 19:16:27.132 SOQ[4923:707] Counter: 32769
2013-05-28 19:16:27.132 SOQ[4923:707] Counter: 32769
My questions here:
1. How does this behavior change from mac to mac? //I was thinking different compiler versions but it was both using the same(not sure though) . Is there any other way?
2. How did the counter get initialized to 32767? I was thinking garbage value, but isn't the objective-c compiler supposed to initialize primitive like int to zero? And I'm getting the same 32769 over and over again. How?
Maybe I'm missing out on something basic. Any pointers?
How did counter get initialized to 1? (when i use static it get initialized to zero)
How is the value being stored over successive method calls?
When I check for the memory location of this variable for different executions of the program it remains the same. How does that happen?
How does this behavior change from mac to mac? //I was thinking different compiler versions but it was both using the same(not sure though) . Is there any other way? 
How did the counter get initialized to 32767? I was thinking garbage value, but isn't the objective-c compiler supposed to initialize primitive like int to zero? And I'm getting the same 32769 over and over again. How?
The answer to all these questions is: coincidence. You are using an uninitialized value. You can't rely on this value, and you should not use it at all. The compiler probably warns you about it too.
The compiler does not initalize local variables of primitive types. If you use ARC local objects are initialized to nil automatically, but not primitive types.
Primitive instance variables are initialized to 0 and instance variables pointing to objects are initialized to nil.
In your incrementCounter function you are using counter which is an uninitialised variable, so the behaviour is 'undefined' - which means what you're seeing is perfectly valid behaviour (in that any behaviour would be valid since the behaviour is undefined).
So as for what is actually happening (or could potentially be happening, depending on the compiler and runtime implementations):
1-1: It's undefined what the initial value will be, but it might end up always being the same for multiple executions if the object loader behaves in a deterministic way and just happens to leave a certain bit-pattern in that memory prior to beginning execution of your program, or even just by accident.
1-2: When incrementCounter is called some memory on the stack is allocated (the next available chunk, on the top of the stack), then incrementCounter increments and returns it. Then NSLog is called, using the same stack-memory (but perhaps a different size). NSLog happens to not trample on that value (probably because the compiler puts it in a place used for return values and NSLog doesn't have a return value). Then incrementCounter is called again, the same stack-memory is re-used and the value just happens to not have been trampled. Try implementing a second otherIncrementCounter method in exactly the same way to see if they are both sharing the same memory for that return value, also take a look at &counter in both methods, it's probably the same.
1-3: The local address-space that your program uses when it is run as a process is local to that process. A different program writing to the same address won't trample your process's memory. A kernel implementation can map this memory however it likes, for example it could use the same starting-point for the stack address space for all its processes.
2-1 & 2-2: See 1-1 and 1-2 above. Perhaps a different build of the kernel, object loader, OS, etc. In this case perhaps NSLog is doing something with that value, perhaps using it temporarily, to set it to 32767 each time. The implementation of NSLog may have changed or may just be compiled with a different compiler version on that machine - it's in a shared library that's loaded and linked at run-time, not compiled into your executable.
In general it's fairly pointless to wonder about these things, there are too many reasons that things could be working as they are, but it's useful to know how compilers and stacks work so I hope my answers above give you inspiration to learn about that a bit more. However, when programming (and not learning about compilers) simply don't rely on undefined behaviour, turn on lots of warnings and treat them as errors so you don't ever accidentally depend on the implementations of compilers, runtimes, or library implementations.

NSString pointer: theoretical questions after study

I have questions about the NSString pointer. I wanted to get to the bottom of this and actually tried to create a theory to obtain full understanding based on multiple information retrieved from then net. Please believe me when I say that I have not been lazy, and I actually read a lot, but I was still left with uncertainties and questions. Can you please confirm / deny when good / wrong, and I've put additional questions and doubts which are indicated by (?).
Here we go:
If I consider this very basic example:
NSString *sPointer = [[NSString alloc]initWithString:#"This is a pointer"];
[sPointer release];
My starting point was: The compiler reserves RAM memory for a pointer type and this memory (which also has an own address) contains the memory address (hexadecimal - binary) of the memory where another variable is stored (where it points to). The actual pointer would take up about 2 bytes:
1) First some general issue - not necessarily linked to objective C. The actual questions about the NSString pointer will come in point 2.
A string is a "string of characters", where 1 character takes a fixed amount of memory space, let's say 2 bytes.
This automatically means that the memory size occupied by a string variable is defined by the length of the character string.
Then I read this on Wikipedia:
"In modern byte-addressable computers, each address identifies a single byte of storage; data too large to be stored in a single byte may reside in multiple bytes occupying a sequence of consecutive addresses. "
So in this case, the string value is actually contained by multiple addresses and not by a single 1 (this already differs from what I read everywhere) (?).
How are these multiple addresses contained in 1 pointer in reality? Will the pointer be divided into multiple addresses as well?
Do you know what component in a computer actually identifies and assigns the actual address "codes"?
And now my actual questions;
2) In my example, the code does 2 things:
It creates a pointer to the address where the string variable is stored.
It also actually saves the actual "String variable": #"This is a pointer", because otherwise there would be nothing to point to;
OK, my question; I wondered what really happens when you release the pointer [sPointer release]; are you actually releasing the pointer (containing the address), or are you also releasing the actual "string variable" from memory as well?
I have learned that when you delete the reference, the memory where the actual variable is stored will just be overwritten at the time the compiler needs memory so it does not need to be cleared at that time. Is this wrong?
If it is correct, why do they say that it's really important to release the NSString pointer for performance reasons, if you just release the pointer which will basically contain only a few bytes? Or am I wrong, and is the memory where the actual variable is stored in fact also cleared at once with the "release" message?
And finally also: primitive datatypes are not released, but they "do" take memory space at the moment of declaration (but not more than a common pointer). Why shouldn't we release them in fact? What prevents us from doing something like: int i = 5, followed by [i release]?;
I'm sorry - a lot of questions in 1 time! In practice, I never had problems with it, but in theory, I also really want to fully understand it - and I hope that I'm not the only one. Can we discuss the topic?
Thank you and sorry for the bother!
Maybe I'm wrong but I just read yesterday that pointers usually take 4 bytes. That answers none of your questions but you seem really interested in this so I figured I would mention it.
I think the source of your confusion is that you are confusing primitives with Objective-C classes. Objective-C classes (or objects to be exact, instances of classes) can accept messages (similar to method invocations in other languages). retain is one such message. This is why an Objective-C NSString object can receive the retain message but not a primitive like an integer. I think that's another one of your confusions. retain and release etc. are not Objective-C language constructs, they're actual messages (think methods) you send to objects. That is why they apply to Objective-C objects but not to primitives like integers and floats.
Another similar confusion is that what you read about how strings are stored has more to do with C-style strings, like char *name = "john". However, when you create a pointer to an NSString, that points to an NSString instance, which itself decides how to handle storing the actual string bytes/characters. Which may or not be the same way that C strings are stored.
data too large to be stored in a single byte may reside in multiple bytes occupying a sequence of consecutive addresses. " So in this case, the string value is actually contained by multiple addresses and not by a single 1 (this already differs from what I read everywhere) (?). How are these multiple addresses contained in 1 pointer in reality?
In C for example, the pointer would point to the address of the first character in the string.
OK, my question; I wondered what really happens when you release the pointer [sPointer release]; are you actually releasing the pointer (containing the address), or are you also releasing the actual "string variable" from memory as well?
You are sending the release message to the NSString instance/object. This is important to note to avoid further confusion. You are not acting upon the pointer itself, but upon what the pointer is pointing to, which is the NSString object. So you are not releasing the pointer itself. After sending the object the release method, if its reference count has reached 0, then it will handle deallocating itself by deallocating everything it stores, which I imagine includes the actual character string.
If it is correct, why do they say that it's really important to release the NSString pointer for performance reasons, if you just release the pointer which will basically contain only a few bytes?
So yeah, you're actually sending the release message to the string instance and it handles how to deallocate itself if it has to. If you were to simply erase the pointer so that it no longer points at the string instance, then you simply will no longer know where/how to access the data stored at that location, but it won't make it magically disappear, the program won't automatically know that it can use that memory. What you're hinting at is garbage collection, in which, simply put, unused memory will automatically be freed for subsequent use. Objective-C 2.0 does have garbage collection but as far as I know it's not enabled on iOS devices yet. Instead, the new version of iOS will support a feature known as Automatic Reference Counting in which the compiler itself takes care of reference counting.
Sorry if I didn't answer all of your questions, you asked a ton :P If any of my information is wrong please let me know! I tried to limit my answer to what I felt I did know.
"Or am I wrong, and is the memory where the actual variable is stored in fact also cleared at once with the "release" message?" The memory IS NOT CLEARED, but goes into the free memory pool, so that it does in fact reduce the memory print of the program. If you did not release the pointer you would continue to "hog" memory until you consume all the virtual memory available and crash not only your program but potentiality the system as well.
How are these multiple addresses contained in 1 pointer in reality?
Will the pointer be divided into multiple addresses as well? Do you
know what component in a computer actually identifies and assigns the
actual address "codes"?
From the perspective of the programmer (take note of this), the pointer on itself is usually a 4-byte number that represents the offset from start from the memory (32-bits, in 64-bit you can have addresses up to 8 bytes). The thing is that this pointers points to the start of whatever is being stored, and that's it.
In C for example, the original strings used a NULL (\0) terminated strings to identify when a string ended (Try doing a printf() on C with a non-zero ended string, and it will print whatever is in memory until it finds a zero). This of course is pretty dangerous, and one has to use functions like strncpy (notice the "n") indicating that you should manually input the number of chars from the offset until it ends.
A way to circumvent this is storing the used space in the start of the memory address, something like
struct
{
int size;
char *string;
}string;
That stores the size to prevent any issues. Objective-C and many other more abstract language implement in their own way how to handle memory. An NSString* is quite an abstract class to know what happens behind the scenes, it probably inherits all its memory managing from the NSObject.
The whole point I'm try to get is that a pointer contains the starting address, and you can jump from byte-to-byte from there (or jumps of a certain size), keeping in mind the total length of whatever you're storing to avoid doing nasty things like overflowing the stack memory (hence, the name of this site).
Now, how the computer gives this addresses is entirely up to the Operating System, and your logical memory address you use in all your programs is quite different from what the underlying implementation uses (physical memory address). Typically, you'll find that memory is stored in segmented units called "frames", and a used frame is called a "page". And the mapping in between physical and logical is done with a "[Page Table]"2.
As you can see, the software handles pretty much everything, but doesn't mean that there isn't hardware to support this, like the TLB, a cpu-level cache that holds recent memory addresses for quick access.
Also, please take my answer with a grain of salt, it's been a while since I studied these subjects.
OK, my question; I wondered what really happens when you release the
pointer [sPointer release]; are you actually releasing the pointer
(containing the address), or are you also releasing the actual "string
variable" from memory as well? I have learned that when you delete the
reference, the memory where the actual variable is stored will just be
overwritten at the time the compiler needs memory so it does not need
to be cleared at that time. Is this wrong? If it is correct, why do
they say that it's really important to release the NSString pointer
for performance reasons, if you just release the pointer which will
basically contain only a few bytes? Or am I wrong, and is the memory
where the actual variable is stored in fact also cleared at once with
the "release" message?
When you release, you're just decreasing the memory count of the object. What you mean is what happens when it's dealloced (when the count reaches zero).
When you dealloc something, you're basically saying that the space where it has been reserved it's now free to be replaced by anything else requesting memory (through alloc). The variable may still point to a freed space, and this causes problems (Read about dangling pointers and leaks).
The memory might be cleared, but there's no guarantees.
I hope this clears all the doubts, as all of them spawn from your confusion about memory freeing.
And finally also: primitive datatypes are not released, but they "do"
take memory space at the moment of declaration (but not more than a
common pointer). Why shouldn't we release them in fact? What prevents
us from doing something like: int i = 5, followed by [i release]?;
The thing is C has two main things going (actually, a lot more): The Heap that stores memory that has been requested with alloc (or malloc in C), and these require to be freed. And the Stack, which holds local variables, that die when the function/block ends (the stack pops the function call).
In your example, the variable i has been locally declared within its scope, and it's contined in the stack. Trying to peform a dealloc/free (also, the variable i won't respond to release, nor dealloc, as it's not an object) won't work, as is not the type of memory which requires to be freed.
I suggest you going back to C before trying to tackle what Objective-C does, because it's hard to have a clear idea how the imperative programming works with all the nice abstractions like release and dealloc.
For the sake of the forum, I will make a brief and simplified summary of your answers as a conclusion. Thanks to all of you for this extended clarification, the mist disappeared! Don't hesitate to react in case you want to add or rectify something:
Rectification: a pointer on the Mac takes 4 bytes of memory space and not 2.
The pointer *sPointer points to an instance of the NSString class and NOT directly to the memory where the chars are saved.
The NSString instance consists of a set of iVars in which there is a pointer iVar that points to memory allocated where the char variables that make up the string are stored (defined when using the initWithString: instance method).
[sPointer release]; The release message is not sent to the pointer itself, but to the instance of the NSString Object. You are not acting on the pointer itself, but on what the pointer is pointing to (!).
When sending the alloc message, the retain count of the NSString instance object is increased by 1. When sending a "release" message it doesn't mean that the concerned memory is literally being emptied, but it decreases the retain count by 1. When the retain count reaches zero, the compiler knows that the previously allocated memory is available again for re-use.
The way memories addresses are presented is decided by the operating system. The logical memory address used in programs is different from what the underlying implementation actually uses (physical memory address).
LOCAL variables (not necessarily primitive variables) are stored in the Stack memory (unlike objects instances who are stored in the Heap memory). What this means is that they will be destroyed automatically at the end of a function (they are automatically removed from the stack). More info on the memory constructs stack and heap can be found in several threads that clarify the use and difference in their own way. e.g.. What and where are the stack and heap? / http://ee.hawaii.edu/~tep/EE160/Book/chap14/subsection2.1.1.8.html
Before I answer the points, you start with a false premise. A pointer takes up more than 2 bytes on a non-16 bit system. On the Mac, it takes up 4 bytes for a 32 bit executable, and 8 bytes in a 64 executable.
Let me note that the following is not entirely accurate (for optimization and some other reasons, there are several kinds of internal representations of strings and the initXXX functions decide which is instantiated), but for the sake of use and understandingof strings, the explanation is good enough.
An NSString is a class (and a rather complicated one as well). A string, i.e. an instance of that class, contains some administrative ivars and one that is another pointer which points to a piece of allocated memory big enough to at least hold the bytes/code points that make up the string. Your code (the alloc method, to be precise) reserves enough memory to contain all the ivars of the object (including the pointer to the buffer) and returns a pointer to that memory. That is what you store in your pointer (if initWithString: doesn't change it -- but I won't go into that here, let's assume it doesn't). If necessary, initWithString: allocates the buffer large enough to hold the text of the string and stores its memory in the pointer for it, inside the NSString instance. So it is like this:
sPointer NSString instance buffer
+---------------------------+ +-----------------+ +------+
| addr of NSString instance | ----> | ivar | +-> | char |
+---------------------------+ | ivar | | | char |
| ivar (pointer) | --+ | char |
| ivar | | char |
| etc... | | char |
+-----------------+ | char |
| etc. |
+------+
In the case of a hard-coded, literal string like #"Hello", the internal pointer only points to that string, which is already stored in the program, in readonly memory. No memory has to be allocated for it, and the memory can't be freed either.
But let's assume you have a string with allocated contents. release (either coded manually, or invoked by an autorelease pool) will decrement the reference count of the string object (the so called retainCount). If that count reaches zero, your instance of the NSString class will be dealloced, and in the dealloc method of the string, the buffer holding the string text will be released. That memory is not cleared in any way, it is only marked as free by a memory manager, which means it can be re-used again for some other purpose.

How does it know where my value is in memory?

When I write a program and tell it int c=5, it puts the value 5 into a little bit of it's memory, but how does it remember which one? The only way I could think of would be to have another bit of memory to tell it, but then it would have to remember where it kept that as well, so how does it remember where everything is?
Your code gets compiled before execution, at that step your variable will be replaced by the actual reference of the space where the value will be stored.
This at least is the general principle. In reality it will be way more complecated, but still the same basic idea.
There are lots of good answers here, but they all seem to miss one important point that I think was the main thrust of the OP's question, so here goes. I'm talking about compiled languages like C++, interpreted ones are much more complex.
When compiling your program, the compiler examines your code to find all the variables. Some variables are going to be global (or static), and some are going to be local. For the static variables, it assigns them fixed memory addresses. These addresses are likely to be sequential, and they start at some specific value. Due to the segmentation of memory on most architectures (and the virtual memory mechanisms), every application can (potentially) use the same memory addresses. Thus, if we assume the memory space programs are allowed to use starts at 0 for our example, every program you compile will put the first global variable at location 0. If that variable was 4 bytes, the next one would be at location 4, etc. These won't conflict with other programs running on your system because they're actually being mapped to an arbitrary sequential section of memory at run time. This is why it can assign a fixed address at compile time without worrying about hitting other programs.
For local variables, instead of being assigned a fixed address, they're assigned a fixed address relative to the stack pointer (which is usually a register). When a function is called that allocates variables on the stack, the stack pointer is simply moved by the required number of bytes, creating a gap in the used bytes on the stack. All the local variables are assigned fixed offsets to the stack pointer that put them into that gap. Every time a local variable is used, the real memory address is calculated by adding the stack pointer and the offset (neglecting caching values in registers). When the function returns, the stack pointer is reset to the way it was before the function was called, thus the entire stack frame including local variables is free to be overwritten by the next function call.
read Variable (programming) - Memory allocation:
http://en.wikipedia.org/wiki/Variable_(programming)#Memory_allocation
here is the text from the link (if you don't want to actually go there, but you are missing all the links within the text):
The specifics of variable allocation
and the representation of their values
vary widely, both among programming
languages and among implementations of
a given language. Many language
implementations allocate space for
local variables, whose extent lasts
for a single function call on the call
stack, and whose memory is
automatically reclaimed when the
function returns. (More generally, in
name binding, the name of a variable
is bound to the address of some
particular block (contiguous sequence)
of bytes in memory, and operations on
the variable manipulate that block.
Referencing is more common for
variables whose values have large or
unknown sizes when the code is
compiled. Such variables reference the
location of the value instead of the
storing value itself, which is
allocated from a pool of memory called
the heap.
Bound variables have values. A value,
however, is an abstraction, an idea;
in implementation, a value is
represented by some data object, which
is stored somewhere in computer
memory. The program, or the runtime
environment, must set aside memory for
each data object and, since memory is
finite, ensure that this memory is
yielded for reuse when the object is
no longer needed to represent some
variable's value.
Objects allocated from the heap must
be reclaimed—especially when the
objects are no longer needed. In a
garbage-collected language (such as
C#, Java, and Lisp), the runtime
environment automatically reclaims
objects when extant variables can no
longer refer to them. In
non-garbage-collected languages, such
as C, the program (and the programmer)
must explicitly allocate memory, and
then later free it, to reclaim its
memory. Failure to do so leads to
memory leaks, in which the heap is
depleted as the program runs, risking
eventual failure from exhausting
available memory.
When a variable refers to a data
structure created dynamically, some of
its components may be only indirectly
accessed through the variable. In such
circumstances, garbage collectors (or
analogous program features in
languages that lack garbage
collectors) must deal with a case
where only a portion of the memory
reachable from the variable needs to
be reclaimed
There's a multi-step dance that turns c = 5 into machine instructions to update a location in memory.
The compiler generates code in two parts. There's the instruction part (load a register with the address of C; load a register with the literal 5; store). And there's a data allocation part (leave 4 bytes of room at offset 0 for a variable known as "C").
A "linking loader" has to put this stuff into memory in a way that the OS will be able to run it. The loader requests memory and the OS allocates some blocks of virtual memory. The OS also maps the virtual memory to physical memory through an unrelated set of management mechanisms.
The loader puts the data page into one place and instruction part into another place. Notice that the instructions use relative addresses (an offset of 0 into the data page). The loader provides the actual location of the data page so that the instructions can resolve the real address.
When the actual "store" instruction is executed, the OS has to see if the referenced data page is actually in physical memory. It may be in the swap file and have to get loaded into physical memory. The virtual address being used is translated to a physical address of memory locations.
It's built into the program.
Basically, when a program is compiled into machine language, it becomes a series of instructions. Some instructions have memory addresses built into them, and this is the "end of the chain", so to speak. The compiler decides where each variable will be and burns this information into the executable file. (Remember the compiler is a DIFFERENT program to the program you are writing; just concentrate on how your own program works for the moment.)
For example,
ADD [1A56], 15
might add 15 to the value at location 1A56. (This instruction would be encoded using some code that the processor understands, but I won't explain that.)
Now, other instructions let you use a "variable" memory address - a memory address that was itself loaded from some location. This is the basis of pointers in C. You certainly can't have an infinite chain of these, otherwise you would run out of memory.
I hope that clears things up.
I'm going to phrase my response in very basic terminology. Please don't be insulted, I'm just not sure how proficient you already are and want to provide an answer acceptable to someone who could be a total beginner.
You aren't actually that far off in your assumption. The program you run your code through, usually called a compiler (or interpreter, depending on the language), keeps track of all the variables you use. You can think of your variables as a series of bins, and the individual pieces of data are kept inside these bins. The bins have labels on them, and when you build your source code into a program you can run, all of the labels are carried forward. The compiler takes care of this for you, so when you run the program, the proper things are fetched from their respective bin.
The variables you use are just another layer of labels. This makes things easier for you to keep track of. The way the variables are stored internally may have very complex or cryptic labels on them, but all you need to worry about is how you are referring to them in your code. Stay consistent, use good variable names, and keep track of what you're doing with your variables and the compiler/interpreter takes care of handling the low level tasks associated with that. This is a very simple, basic case of variable usage with memory.
You should study pointers.
http://home.netcom.com/~tjensen/ptr/ch1x.htm
Reduced to the bare metal, a variable lookup either reduces to an address that is some statically known offset to a base pointer held in a register (the stack pointer), or it is a constant address (global variable).
In an interpreted language, one register if often reserved to hold a pointer to a data structure (the "environment") that associates variable names with their current values.
Computers ultimately only undertand on and off - which we conveniently abstract to binary. This language is the basest level and is called machine language. I'm not sure if this is folklore - but some programmers used to (or maybe still do) program directly in machine language. Typing or reading in binary would be very cumbersome, which is why hexadecimal is often used to abbreviate the actual binary.
Because most of us are not savants, machine language is abstracted into assembly language. Assemply is a very primitive language that directly controls memory. There are a very limited number of commands (push/pop/add/goto), but these ultimately accomplish everything that is programmed. Different machine architectures have different versions of assembly, but the gist is that there are a few dozen key memory registers (physically in the CPU) - in a x86 architecture they are EAX, EBX, ECX, EDX, ... These contain data or pointers that the CPU uses to figure out what to do next. The CPU can only do 1 thing at a time and it uses these registers to figure out what to do next. Computers seem to be able to do lots of things simultaneously because the CPU can process these instructions very quickly - (millions/billions instructions per second). Of course, multi-core processors complicate things, but let's not go there...
Because most of us are not smart or accurate enough to program in assembly where you can easily crash the system, assembly is further abstracted into a 3rd generation language (3GL) - this is your C/C++/C#/Java etc... When you tell one of these languages to put the integer value 5 in a variable, your instructions are stored in text; the assembler compiles your text into an assembly file (executable); when the program is executed, the program and its instructions are queued by the CPU, when it is show time for that specific line of code, it gets read in the the CPU register and processed.
The 'not smart enough' comments about the languages are a bit tongue-in-cheek. Theoretically, the further you get away from zeros and ones to plain human language, the more quickly and efficiently you should be able to produce code.
There is an important flaw here that a few people make, which is assuming that all variables are stored in memory. Well, unless you count the CPU registers as memory, then this won't be completely right. Some compilers will optimize the generated code and if they can keep a variable stored in a register then some compilers will make use of this!
Then, of course, there's the complex matter of heap and stack memory. Local variables can be located in both! The preferred location would be in the stack, which is accessed way more often than the heap. This is the case for almost all local variables. Global variables are often part of the data segment of the final executable and tend to become part of the heap, although you can't release these global memory areas. But the heap is often used for on-the-fly allocations of new memory blocks, by allocating memory for them.
But with Global variables, the code will know exactly where they are and thus write their exact location in the code. (Well, their location from the beginning of the data segment anyways.) Register variables are located in the CPU and the compiler knows exactly which register, which is also just told to the code. Stack variables are located at an offset from the current stack pointer. This stack pointer will increase and decrease all the time, depending on the number of levels of procedures calling other procedures.
Only heap values are complex. When the application needs to store data on the heap, it needs a second variable to store it's address, otherwise it could lose track. This second variable is called a pointer and is located as global data or as part of the stack. (Or, on rare occasions, in the CPU registers.)
Oh, it's even a bit more complex than this, but already I can see some eyes rolling due to this information overkill. :-)
Think of memory as a drawer into which you decide how to devide it according to your spontaneous needs.
When you declare a variable of type integer or any other type, the compiler or interpreter (whichever) allocates a memory address in its Data Segment (DS register in assembler) and reserves a certain amount of following addresses depending on your type's length in bit.
As per your question, an integer is 32 bits long, so, from one given address, let's say D003F8AC, the 32 bits following this address will be reserved for your declared integer.
On compile time, whereever you reference your variable, the generated assembler code will replace it with its DS address. So, when you get the value of your variable C, the processor queries the address D003F8AC and retrieves it.
Hope this helps, since you already have much answers. :-)