void uc(char* s)
{
int i;
for( i=0; i < strlen(s); i++ )
if (97 <= s[i] && s[i] <= 122)
s[i] = s[i] - 32;
return;
}
My professor showed our class this operator.
char* s
copies an array, this is ok because an array name is it's first element memory address.
Now my problem is: why do we treat the pointer s
as an array in the for
cycle?
Pointers store addresses, but I learnt they don't have a very intuitive behaviour...
My problem is that I consider them "as an int variable", since memory address are integers in an hexadecimal format (right?), but i know it's not so simple.
Edit: thank you all for the answers, I'm loving this site and community <3 As you witnessed I'm a newbie, so thank you for the patience and the nice explanations
First things first, and being completely blunt:
Your mental model is wrong! It is imperative, that you're correcting your misconceptions now, before you're in too deep.
char* s
copies an array,
This is a misconception. s
is a pointer to a char
. It could be a single char
or a whole array. The exact type of the underlying object is lost when taking an address.
Nothing is copied, though! It's just a pointer to "wherever" (waves around with arms) and everyone involved (you, the compiler, other programmers) are in an unspoken and unwritten agreement to be nice and not doing something stupid. Like passing in a pointer that later in the function will be used in an invalid way.
this is ok because an array name is it's first element memory address.
Arrays don't have names! Symbols do. The symbol to an array will decay to a pointer to the elementary type of which the array is made from. This decay is why you can write char somearray[123]; char *p = somearray
without taking its address.
why do we treat the pointer s as an array in the for cycle?
Because we can. More specifically because of this thing called "pointer arithmetic". The expession s + 1
will result in a pointer that points one element past the address of the element the pointer is pointing to. It works for any number (within the value range of ptrdiff_t
).
When you write a_pointer[i]
in C, it literally translates (that's not hyperbole, the C standard requires it to be treated by the compiler being done like that!) into *(a_pointer + i)
. So what happens is that by writing a_pointer[i]
you're telling the compiler: *"assume that a_pointer
points into an array object and that a_pointer + i
is still inside the bounds of that array object: With that assumption, dereference that location and produce the value there."
However the results of pointer arithmetic are defined only, if the resulting pointer stays within the bounds of an object.
Do pointer arithmetic on a pointer that's not taken from an array? Undefined!
Generate a pointer that's outside the bounds of an array? Undefined!
My problem is that I consider them "as an int variable",
They're not! Technically pointers may be implemented by unicorn dust and magic. There are a few very specific rules to them, when it comes to intermingling them with numbers. In the C programming language these rules are (simplified):
Pointers can be translated into integers of size sizeof(uintptr_t)
and vice versa.
The numeric value 0 translates to the null pointer, and null pointers translate to the numeric value 0.
Null pointers are invalid and hence must not be dereferenced.
Pointers can be subtracted from each other, resulting in an integer compatible to ptrdiff_t
, and the value of the resulting integer is the distance in elements between these two pointers, assuming that both pointers refer to the same object. Written in "types" ⟪ptrdiff_t⟫ = ⟪pointer A⟫ - ⟪pointer B⟫
, only arithmetic valid rearrangements of this are valid.
You can't add pointers
You can't multiply pointers
There is no mandate that number representations of pointers can be used for pointer arithmetic. I.e. you must not assume that (pointer_A - pointer_B) == k*((uintptr_t)pointer_A - (uintptr_t)pointer_B))
for any value of k
.
since memory address are integers in an hexadecimal format (right?),
Huh?!? This is not how things work.
Yes, you can use integers to address memory location. No, you don't have to write them as hexadecimals. Hexadecimal is just a different number base and 0xF == 15 = 0o17 == 0b1111. These days we usually write addresses in hexadecimal because it nicely aligns with our current computer architectures' word sizes being powers of 2. One hexadecimal digit equals 4 bits. But there are other architectures that use different word sizes and on those other number bases are better suited.
And that still assumes linear address spaces. There are however also computer architectures that support segmented address spaces. As a matter of fact, it is very likely that the machine you're reading this on is such a computer. If it's using a CPU made by Intel or AMD, this thing actually understands segmented addresses https://en.wikipedia.org/wiki/X86_memory_segmentation
In x86 segmented address space an address actually consists of two numbers, i.e. it forms a vector. Which means if you're compiling a C program to run in a segmented address space environment pointer types no longer will be simple singular value numbers. C still requires them to be translatable to uintptr_t though, ponder on that!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With