If we have a string "A" and a number 65, since they look identical in memory, how does the OS know which is the string and which is the number?
Another question – assume that a program allocates some memory (say, one byte). How does the OS remember where that memory has been allocated?
Neither of these details are handled by the operating system. They’re handled by user programs.
For your first question, internally in memory there is absolutely no distinction between the character ‘A’ and the numeric value 65 (assuming, of course, that you’re just looking at one byte of data). The difference arises when you see how those bits are interpreted by the program. For example, if the user program tries to print the string to the screen, it will probably make some system call to the OS to ask the OS to print the character. In that case, the code in the OS consists of a series of assembly instructions to replicate those bits somewhere in the display device. The display is then tasked with rendering a set of appropriate pixels to draw the character ‘A.’ In other words, at no point did the program ever “know” that the value was an ‘A.’ Instead, the hardware simply pushed around bits which controlled another piece of code that ultimately was tasked with turning those bits into pixels.
For your second question, that really depends on the memory manager. There are many ways for a program to allocate memory and know where it’s stored. I’m not fully sure I understand what you’re asking, but I believe that this answer should be sufficient:
At the OS level, the OS kernel doesn’t even know that the byte was allocated. Instead, the OS just allocates giant blocks of memory for the user program to use as it runs. When the program terminates, all that memory is reclaimed.
At the program level, most programs contain a memory manager, a piece of code tasked with allocating and divvying up that large chunk of memory into smaller pieces that can then be used by the program. This usually keeps track of allocated memory as a list of “chunks,” where each chunk of memory is treated as a doubly-linked list of elements. Each chunk is usually annotated with information indicating that it’s in use and how large the chunk is, which allows the memory manager to reclaim the memory once it’s freed.
At the user code level, when you ask for memory, you typically store it in a pointer to keep track of where the memory is. This is just a series of bytes in memory storing the address, which the OS and memory manager never look at unless instructed to.
Hope this helps!