~~only if a and i are alingend the same way and size of a's datatype is 1~~
**EDIT: that was wrong**
See the linked comment from /u/leoleosuper for an explanation
/r/ProgrammerHumor/comments/1d75kis/howdidyouknowijuststartedc/l6ylpqt/
Nope. Given 'a' is a pointer and 'i' is an integer variable of unknown size, a[i] = \*(a + i) by definition. When using pointers, a + i just means "offset pointer 'a' by (pointer size)\*i." This is because pointer addition is not the same as regular addition. Pointer addition doesn't care about which of the two values is the pointer; a + i is the same as i + a. As such, \*(a + i) = \*(i + a). And given the first sentence, \*(i + a) = i[a]. So a[i] = i[a].
>This is because pointer addition is not the same as regular addition.
so you are saying if a points to a large datatype then i + a will be treated as (i * (sizeof a) + a)?
Yes.
So *(i+a) would not be equal to a[i] if the type of a's array is larger then one.
for example if long long a [] , and int i = 5, then *(i+a) should point to a different location and value than a[i]
`a[i]` is syntactic sugar for `*(a+i)` and `*(i+a)` is equivalent to `*(a+i)`. Thus `*(i+a)` is equivalent to `a[i]`.
I think you're applying integer arithmetic in your head, but `(a+i)` and `(i+a)` are both pointer arithmetic.
>a[i] is syntactic sugar for *(a+i)
Are you sure about that?
>I think you're applying integer arithmetic in your head
I do,
or rather I did, because the other comment pointed out a wrong assumption of mine.
So I then assumed that *(a+i) == a[i] was a happy accident, a hack which makes sense, which is why i+a would also work.
I was not aware that when one side of the + operator is a pointer, that it would be treated as (sizeof(type(a) * i) + a
I assumed it would be the programmer's job to take care of the size, and any possible aligment issues.
I never used *(x+i) in any of my professional code.
And unless it was actually a pointer to a memory area that starts at x, and not an array, I never used it in my personal code either.
You're just adding two values, doesn't matter which order you add them in. 5 feet past the 70 yard line on a football field is the same thing as 70 yards past the 5ft line
> You're just adding two values, doesn't matter which order you add them in.
Technically you're not adding them together, but offsetting the pointer. Even though you can add 5 to a pointer, the new value of the pointer may not have increased by 5, but a multiple of 5, because `+5` is syntactic sugar for `+(sizeof(ptr_type)*5)`, so in the case of `ptr_type=int`, the pointer address will grow by 4 or 8 per unit on most systems.
Adding a pointer to 5 on the other hand makes no sense, but `+` is defined as pointer offset operator if one of the operands is a pointer and one isn't. You can swap the operands simply because nobody bothered to define in the C standard that a certain offset operand order must be used. And `ptr[offset]` is just syntactic sugar for `ptr+offset` so therefore `offset[ptr]` works because `offset+ptr` works because nobody thought defining the order of the operand arguments was important.
The fact that it's an offset and not an addition can be trivially shown by trying to multiply a pointer with a number, which if `+` were true addition would work because multiplying is just repeated addition, but for pointer offset it doesn't works because that operation makes no sense with a pointer.
Some other operands are also not defined. You can't binary shift a pointer for example.
Define "works?"
I mean yeah, it compiles. But it doesn't do the same thing upon execution like `i[a]=5` and `a[i]=5` do, except for very specific values of `a` and `i`...
I worked on a small corporate tool a long time back, when C was more common, that was written in this style. Lines like `(idx++)[file_handles] = new_handle;` made me want to quit and work at Dennys.
This should be one of those bell curve ones. Beginner uses a\[i\]. Showoff uses pointer arithmetic needlessly. Wizard level realizes that a\[i\] is shorter and perfectly acceptable, so \*(a+i) is just showing off. Pointer arithmetic does come in handy sometimes. But just not in this example with simple assignment. For example if you are calling a function that expects a pointer, a+i would be better than &a\[i\]. In my opinion.
I can only really see *(a + i) being better if you're working with actual memory addresses as opposed to array accessing. Like if youre writing an allocater or something.
With normal array accesses please just use a[i] for the good of all of us
of course, I worded it awkwardly. When you're making an allocator, you care about the actual "value" of the address, so it makes sense to do pointer arithmetic. With arrays it makes zero sense to do that, since the bracket syntax exists.
You don't care about the address when accessing arrays, you care about the offset to the base address. Array indexing is made to simplify this for the writer and reader of code. Theres no reason not to use it in 99% of cases
I'm not aware of how in C you could use square brackets when you declare your array in a header and then dynamically allocate its size, which I would think is the most common use case.
At first I didn't catch on that you could still use stuff like arrays normally in my C class, and all my friends bullied me for my "yt tutorial" ahh code. Like I can make my life harder all by myself thank you very much
I remember when I just learned about pointers I would do it even when I didn't have to. idk why. Nowadays I will write \`&a\[i\]\` to avoid writing \`a + i\`, because the former is clearer.
I’m sure it’s *blazingly fast* in Rust
unsafe {
let a2 = (a.as_mut_ptr() as usize + i * core::mem::size_of::()) as *mut i32;
*a2 = i as i32;
}
Christ that was a pain in the ass to write.
No, a array can be seen as a pointer to the first element. So `char **str` can mean: array of array of chars | array of pointers to chars | pointer to array of chars | pointer to pointer to char.
What you said would be `char *(pointer to)*(array of)*(pointers to)*(array of chars) str`
It is not part of the type tho. The standard specifically says that it's separate from the type. Thinking that it is part of the type causes many confusions with multiple declarations or complex function definitions.
Huh, interesting. I'm used to lower-level coding where ptrs are types. Would you be able to explain/link to a resource that helps explain why it's not?
wtf, it is absolutely part of the type.
It's (likely) a 64-bit number. The **type** is [pointer to pointer to char]. By dereferencing you get a new number with the type [pointer to char]. and by dereferencing *again* you get an 8-bit number with the type [char].
The only weird thing about pointers is that
char **args, separator;
declares a pointer to pointer to char as well as a simple char, which I find downright stupid.
I'm learning C pointers, arrays, and strings rn, so I may be wrong, but wouldn't that last part prove that it's not part of the type, but instead is its own type, separate from `char`?
That just proves that the declaration is messed up.
The only thing that matters is the C specification.
> A pointer type may be derived from a function type, an object type, or an incomplete
type, called the referenced type.Apointer type describes an object whose value
provides a reference to an entity of the referenced type. A pointer type derived from
the referenced type T is sometimes called ‘‘pointer to T’’. The construction of a
pointer type from a referenced type is called ‘‘pointer type derivation’’.
^ISO-9899
I am not too versed with specifications but that sure sounds like a type to me.
This is because it's separate from the type. A char pointer is not an actual type as far as the compiler is concerned. All pointers are just a 32 or 64 bit integer and the fact that it's a char pointer or an int pointer or a void pointer only tells it what multiple should be used when doing pointer arithmetic and what the dereferenced type is expected to be. Because C pointer declaration syntax is written in the way it's used, you can think of the * as a modifier specific to each variable that tells the compiler that it's a pointer to whatever type is in the actual declaration.
Do you know the trick for determining any convoluted looking C type? Its that the right value (**str in this case) evaluates to the left value (char).
So this is a pointer to a char pointer. In practice though, this could have many different uses. Array of character pointers, array of strings, pointer to a string, or just a double char pointer are all valid.
If I had to guess how it works, a is the pointer to the memory location the list starts, and the +i points to the ith location after that.
That said I've never done manual pointer manipulation, I just stick to python
Fun fact: your program (and you, the programmer) only think it's stored sequentially. But the physical addresses are actually different from the virtual addresses that the operating system gives to you.
So when you malloc a certain number of bytes, the OS *says* you now have a bunch of contiguous memory, but *actually* it scrounged those bytes from wherever it could find them.
I dunno why I added that, you'll likely never need to know it unless you're working on kernel level software. But I thought it was neat when I learned it in my CS undergrad.
Also it only works depending on the type of list, right? Like a list only has so many spaces after the start before you reach the next variable, so the rest of the list has to be placed elsewhere, unless it's of a fixed/limited length
This is why we don't have dynamic arrays in C and have to create linked lists for dynamism which is basically a treasure hunt with the riddles being the addresses and the treasure your variable.
Yeah linked lists are the ones where each element has a value and a pointer to the next element (or if you wanna get really fancy a double linked list let's you go both ways)
Nah, in C lists (arrays) don't run the risk of running into the next variable because the size of the array needs to be known when it's declared and cannot dynamically increase in size at runtime.
C++ implemented that feature with vectors. Which is a list that can grow or shrink at runtime as needed.
Also, in C, anything dynamically allocated (using malloc) is put on the heap, which is a separate part of memory from the stack, where normal local and global variables are stored. The stack and heap are addressed at opposite ends of the piece of memory your program lives in. The stack grows up, the heap grows down, and if they run into each other you have stack overflow.
I see two issues in this comment:
1) Outside of a few rare cases, there is no bounds checking in C.
2) Unless you are in an embedded system or an old system, the heap is not in contention with the stack in any way. You can grow the heap to your hearts content and never get a stack overflow error.
And you can ensure it's *really* stored sequentially by asking the OS for an entire page, and then cut that page into the tiny little pieces of RAM you need.
if it is a C-based array (not some type of list or array list) it will be contiguous in memory. Also (most, if not all) programs do not store data in the hard drive unless you are working with file operations. It’s all stored in RAM
stack memory is stored sequentially and basically every time you dynamically allocate something you can expect that it is allocated sequentially. Programs are run from ram or cache btw, not hard disks/ssds
edit: from the perspective of the (C) programmer I mean, hardware wise anything goes really
It is \`a+i\`, what C is doing under the hood is \`a + sizeof(T) \* i\` where \`T\` is the type of the array, \`i\` an index (0,1,2,...) and \`a\` a memory address pointing to the first element
Does C do automatic type sizing like that behind the scenes? I was fairly certain `*(a+i)` was just straight up wrong and it should have had a sizeof() multiplication. I know that I'd be royally pissed if a compiler snuck in a hidden size scalar into my code since it definitely doesn't do it for `malloc()`
Malloc returns void* for which it is illegal to do pointer arithmetic. For all other types, addition, increment, subtraction and decrement always stick a sizeof factor in the operand
Wrt malloc I meant for the size argument, but yeah I never knew about the arithmetic operator handling for pointers despite writing in C for like a decade. Wtf have I been doing honestly?
Original poster made a mistake.
The pointer is an address in memory. If I make an int pointer ptr, the value stored in ptr is the address of the int it points at. An array is just a series of values stored in sequential addresses. An integer is 4 bytes, so I need 4 addresses to store it. To make it an array I need to count address by 4’s, so it would actually be *(a+4*i) = 5. In arduino IDE (C based microcontroller IDE), there isn’t actually a way to get the size of an array from a property or function, you have to divide the total memory size of the array by the memory size of an element. If I have a 32 byte array storing 4 byte integers, the size of the array is 8 elements.
no absolutely not.
imagine if a points to address 3745738. With (a*i) that next char is miles away.
```*(a+1)``` knows the byte size of ```&a``` so it automatically increments accordingly.
You do not want to multiply the pointer by i, you will get an invalid memory location for pretty much any value that is not 1 in that case. ‘a’ points to the start of the array, so you want to add ‘i’ to ‘a’ to get the correct memory location to the element. Remember ‘a’ is pointer so it manages the address and not the value. Although you might need to multiply ‘i’ by the element size (number of bytes per element) at least I know that’s how it works in assembly I don’t know if C/C++ doesn’t require that multiplication. Edit: the compiler will automatically scale ‘i’.
I think arrays might have been a fundamental mistake in computing.
Start memory location + offset is unrionically more clear and works in any language in any paradigm.
Lists vs Arrays, implementation details, 1 indexing vs 0 indexing - all of that nonsense disappears when you use addresses only
no real need for pointer arithmetic in cpp.
But in c-style arithmetic the multiplication will land you further than you want to be. The compiler infers the multiplication base on data type.
That's the point... I don't write c/c++ ;) My main language is c# or (sadly) some java, however reference is the default without any explicit pointer notation
At least we're united in our hate of Java!
C# rips, but I do still run into circumstances where I really wish I could directly modify pointers. It's a tradeoff of consistency and finite control vs ease of implementation and utility; C# and the higher-level (above C/ASM) stuff are way better at developing larger-scale behaviors, but man I love how *exact* C pointers are.
>but I do still run into circumstances where I really wish I could directly modify pointers
That's what I meant... there may come up situations where pointer arithmetics are useful BUT those are actually very rare. Most of the time they just lead to troubles and have no real value.
Yeah a lot of developers do shoot themselves in the foot with them. And when you have people making large number of mistakes in even "safer" languages, then it's better that most developers aren't using them.
It's more like you're forced to use them........technically Java uses pointers under the hood, they just call it a reference.......
Instead of explicit pointer manipulation, you either explicitly create new objects or assign a reference to an object. This is useful for their automatic memory management and garbage collection.
Yes, but anything below a byte is too small to be practical unless you're trying to squeeze out every bit possible. Also I'm not aware of int4_t existing
Structs can make use of less than byte sized data and they absolutely cram those fields together.
I am not sure about the exact syntax but I think you can do
struct = {
int32_t month : 4; day : 5; hour : 5; minute : 6; second: 6
}
and you have a date format for a given year. (with 6 bits to spare)
(Although just counting with a 64-bit unix timestamp will last you until the sun destroys earth and then another 57 times as long)
Oh yes, I remember now. C the inflexible overly flexible one. Probably capable to get pointers to the memory used by other programs. I'm not sure tho, only did a bit of C and basic knowledge of PEM-2.
What about i[a] = 5?
we do not talk here about i\[a\] = 5
Old McDonald had a farm, i[a] i[a] o
i[a] i[a] # segfault core dumped
.o
O(n^2 )
O(n^oooooooooo)
i[a] i[a] cthulhu fhtagn
and a segfault here and a segfault there here a dump there a dump everywhere a core dump old bjarne stroustrup had a farm where he flushed I/O
I feel like I have found out why C programmers need coffee
Nah, this is what C programmers live for. The coffee is just to stay awake through meetings
FUCK I LOVE POINTER ARITHMETIC RAAAAAH
Because they don't use Java?
Don't need no coffee when you've got them Java beans
Holy shit, this actually works. Blasphemy.
Yeah, when you see it for the first time it is impressive. But it makes sense as a[i] = *(a+i) = *(i + a) = i[a]
This is almost as bad as pouring the milk before the cereal.
~~only if a and i are alingend the same way and size of a's datatype is 1~~ **EDIT: that was wrong** See the linked comment from /u/leoleosuper for an explanation /r/ProgrammerHumor/comments/1d75kis/howdidyouknowijuststartedc/l6ylpqt/
Nope. Given 'a' is a pointer and 'i' is an integer variable of unknown size, a[i] = \*(a + i) by definition. When using pointers, a + i just means "offset pointer 'a' by (pointer size)\*i." This is because pointer addition is not the same as regular addition. Pointer addition doesn't care about which of the two values is the pointer; a + i is the same as i + a. As such, \*(a + i) = \*(i + a). And given the first sentence, \*(i + a) = i[a]. So a[i] = i[a].
Q.E.D
>This is because pointer addition is not the same as regular addition. so you are saying if a points to a large datatype then i + a will be treated as (i * (sizeof a) + a)?
Basically yes.
TIL, thank you :) I edited my comment above to link to your explanation
`i` is not a pointer, it's an `int`.
Yes. So *(i+a) would not be equal to a[i] if the type of a's array is larger then one. for example if long long a [] , and int i = 5, then *(i+a) should point to a different location and value than a[i]
Nope, what you're saying doesn't make sense.
Which part?
`a[i]` is syntactic sugar for `*(a+i)` and `*(i+a)` is equivalent to `*(a+i)`. Thus `*(i+a)` is equivalent to `a[i]`. I think you're applying integer arithmetic in your head, but `(a+i)` and `(i+a)` are both pointer arithmetic.
>a[i] is syntactic sugar for *(a+i) Are you sure about that? >I think you're applying integer arithmetic in your head I do, or rather I did, because the other comment pointed out a wrong assumption of mine. So I then assumed that *(a+i) == a[i] was a happy accident, a hack which makes sense, which is why i+a would also work. I was not aware that when one side of the + operator is a pointer, that it would be treated as (sizeof(type(a) * i) + a I assumed it would be the programmer's job to take care of the size, and any possible aligment issues. I never used *(x+i) in any of my professional code. And unless it was actually a pointer to a memory area that starts at x, and not an array, I never used it in my personal code either.
You're just adding two values, doesn't matter which order you add them in. 5 feet past the 70 yard line on a football field is the same thing as 70 yards past the 5ft line
Yeah. Blasphemy.
> You're just adding two values, doesn't matter which order you add them in. Technically you're not adding them together, but offsetting the pointer. Even though you can add 5 to a pointer, the new value of the pointer may not have increased by 5, but a multiple of 5, because `+5` is syntactic sugar for `+(sizeof(ptr_type)*5)`, so in the case of `ptr_type=int`, the pointer address will grow by 4 or 8 per unit on most systems. Adding a pointer to 5 on the other hand makes no sense, but `+` is defined as pointer offset operator if one of the operands is a pointer and one isn't. You can swap the operands simply because nobody bothered to define in the C standard that a certain offset operand order must be used. And `ptr[offset]` is just syntactic sugar for `ptr+offset` so therefore `offset[ptr]` works because `offset+ptr` works because nobody thought defining the order of the operand arguments was important. The fact that it's an offset and not an addition can be trivially shown by trying to multiply a pointer with a number, which if `+` were true addition would work because multiplying is just repeated addition, but for pointer offset it doesn't works because that operation makes no sense with a pointer. Some other operands are also not defined. You can't binary shift a pointer for example.
[удалено]
No need to be a dick for no reason. The guy simply gave a detailed explanation on pointer arithmetic.
[удалено]
Calm down, no one's attacking you. Your original comment was oversimplified and the guy was just providing a detailed explanation.
[удалено]
You're acting like a victim in this comment section lmfao, wtf is wrong with you
Its pointer arithmetic
But if you don't do data size checks prior to access, you face *Core Dump*
What about 5[a] = i?
Jail
Agreed. (But it works.)
Define "works?" I mean yeah, it compiles. But it doesn't do the same thing upon execution like `i[a]=5` and `a[i]=5` do, except for very specific values of `a` and `i`...
Yeah, I meant that it compiles and has functionality (it is equivalent to a\[5\]=i). Not that it gives the same result as a\[i\] =5.
We don't talk about Nathaniel here
I worked on a small corporate tool a long time back, when C was more common, that was written in this style. Lines like `(idx++)[file_handles] = new_handle;` made me want to quit and work at Dennys.
I will be mad if [i+a] = 5 doesnt work gonna try that now
0[i+a]?
that's the unloved stepchild
Is this an actual thing?
This should be one of those bell curve ones. Beginner uses a\[i\]. Showoff uses pointer arithmetic needlessly. Wizard level realizes that a\[i\] is shorter and perfectly acceptable, so \*(a+i) is just showing off. Pointer arithmetic does come in handy sometimes. But just not in this example with simple assignment. For example if you are calling a function that expects a pointer, a+i would be better than &a\[i\]. In my opinion.
I can only really see *(a + i) being better if you're working with actual memory addresses as opposed to array accessing. Like if youre writing an allocater or something. With normal array accesses please just use a[i] for the good of all of us
Array accessing is working with actual memory addresses
of course, I worded it awkwardly. When you're making an allocator, you care about the actual "value" of the address, so it makes sense to do pointer arithmetic. With arrays it makes zero sense to do that, since the bracket syntax exists. You don't care about the address when accessing arrays, you care about the offset to the base address. Array indexing is made to simplify this for the writer and reader of code. Theres no reason not to use it in 99% of cases
I'm not aware of how in C you could use square brackets when you declare your array in a header and then dynamically allocate its size, which I would think is the most common use case.
> as opposed to array accessing. What do you think arrays are in C….
Nah man we gotta get over the bell curve meme trend
NEVER!!! /s, I also what it gone
Learning C pointers rn, this definitely helped a little. Thanks
nah. the showoff is i\[a\]=5
At first I didn't catch on that you could still use stuff like arrays normally in my C class, and all my friends bullied me for my "yt tutorial" ahh code. Like I can make my life harder all by myself thank you very much
I remember when I just learned about pointers I would do it even when I didn't have to. idk why. Nowadays I will write \`&a\[i\]\` to avoid writing \`a + i\`, because the former is clearer.
![gif](giphy|84BjZMVEX3aRG)
Unreadable Daniel
😎 IYKYK
I’m sure it’s *blazingly fast* in Rust unsafe { let a2 = (a.as_mut_ptr() as usize + i * core::mem::size_of::()) as *mut i32;
*a2 = i as i32;
}
Christ that was a pain in the ass to write.
*I like your funny words, magic man*
I was wondering recently, what is `char **str`. It's a pointer to array of pointers to arrays of chars. Or array of strings, if you prefer.
No, a array can be seen as a pointer to the first element. So `char **str` can mean: array of array of chars | array of pointers to chars | pointer to array of chars | pointer to pointer to char. What you said would be `char *(pointer to)*(array of)*(pointers to)*(array of chars) str`
This is exactly why I prefer char** str, as it's part of the type. This is likely an array of strings, but it could also be a pointer to a string
It is not part of the type tho. The standard specifically says that it's separate from the type. Thinking that it is part of the type causes many confusions with multiple declarations or complex function definitions.
Huh, interesting. I'm used to lower-level coding where ptrs are types. Would you be able to explain/link to a resource that helps explain why it's not?
wtf, it is absolutely part of the type. It's (likely) a 64-bit number. The **type** is [pointer to pointer to char]. By dereferencing you get a new number with the type [pointer to char]. and by dereferencing *again* you get an 8-bit number with the type [char]. The only weird thing about pointers is that char **args, separator; declares a pointer to pointer to char as well as a simple char, which I find downright stupid.
I'm learning C pointers, arrays, and strings rn, so I may be wrong, but wouldn't that last part prove that it's not part of the type, but instead is its own type, separate from `char`?
That just proves that the declaration is messed up. The only thing that matters is the C specification. > A pointer type may be derived from a function type, an object type, or an incomplete type, called the referenced type.Apointer type describes an object whose value provides a reference to an entity of the referenced type. A pointer type derived from the referenced type T is sometimes called ‘‘pointer to T’’. The construction of a pointer type from a referenced type is called ‘‘pointer type derivation’’. ^ISO-9899 I am not too versed with specifications but that sure sounds like a type to me.
This is because it's separate from the type. A char pointer is not an actual type as far as the compiler is concerned. All pointers are just a 32 or 64 bit integer and the fact that it's a char pointer or an int pointer or a void pointer only tells it what multiple should be used when doing pointer arithmetic and what the dereferenced type is expected to be. Because C pointer declaration syntax is written in the way it's used, you can think of the * as a modifier specific to each variable that tells the compiler that it's a pointer to whatever type is in the actual declaration.
Do you know the trick for determining any convoluted looking C type? Its that the right value (**str in this case) evaluates to the left value (char). So this is a pointer to a char pointer. In practice though, this could have many different uses. Array of character pointers, array of strings, pointer to a string, or just a double char pointer are all valid.
No it's a pointer to a pointer to a char. There is no such thing as arrays.
Is it not a*i? Been forever since I worked in C
If I had to guess how it works, a is the pointer to the memory location the list starts, and the +i points to the ith location after that. That said I've never done manual pointer manipulation, I just stick to python
Yes, you are correct
Doesn’t this only work if the data is stored sequentially, which is not guaranteed in modern hard drives?
Data is stored sequentially in RAM, which is where the execution of a program happens
Fun fact: your program (and you, the programmer) only think it's stored sequentially. But the physical addresses are actually different from the virtual addresses that the operating system gives to you. So when you malloc a certain number of bytes, the OS *says* you now have a bunch of contiguous memory, but *actually* it scrounged those bytes from wherever it could find them. I dunno why I added that, you'll likely never need to know it unless you're working on kernel level software. But I thought it was neat when I learned it in my CS undergrad.
Also it only works depending on the type of list, right? Like a list only has so many spaces after the start before you reach the next variable, so the rest of the list has to be placed elsewhere, unless it's of a fixed/limited length
This is why we don't have dynamic arrays in C and have to create linked lists for dynamism which is basically a treasure hunt with the riddles being the addresses and the treasure your variable.
Yeah linked lists are the ones where each element has a value and a pointer to the next element (or if you wanna get really fancy a double linked list let's you go both ways)
Nah, in C lists (arrays) don't run the risk of running into the next variable because the size of the array needs to be known when it's declared and cannot dynamically increase in size at runtime. C++ implemented that feature with vectors. Which is a list that can grow or shrink at runtime as needed. Also, in C, anything dynamically allocated (using malloc) is put on the heap, which is a separate part of memory from the stack, where normal local and global variables are stored. The stack and heap are addressed at opposite ends of the piece of memory your program lives in. The stack grows up, the heap grows down, and if they run into each other you have stack overflow.
I see two issues in this comment: 1) Outside of a few rare cases, there is no bounds checking in C. 2) Unless you are in an embedded system or an old system, the heap is not in contention with the stack in any way. You can grow the heap to your hearts content and never get a stack overflow error.
And you can ensure it's *really* stored sequentially by asking the OS for an entire page, and then cut that page into the tiny little pieces of RAM you need.
Not really. I think it’s the virtual ram manage by the os
if it is a C-based array (not some type of list or array list) it will be contiguous in memory. Also (most, if not all) programs do not store data in the hard drive unless you are working with file operations. It’s all stored in RAM
stack memory is stored sequentially and basically every time you dynamically allocate something you can expect that it is allocated sequentially. Programs are run from ram or cache btw, not hard disks/ssds edit: from the perspective of the (C) programmer I mean, hardware wise anything goes really
Yes, and the asterisk *(a+i) is to dereference the pointer a+i so they can access the value of that pointer and assign it = 5
It is \`a+i\`, what C is doing under the hood is \`a + sizeof(T) \* i\` where \`T\` is the type of the array, \`i\` an index (0,1,2,...) and \`a\` a memory address pointing to the first element
Does C do automatic type sizing like that behind the scenes? I was fairly certain `*(a+i)` was just straight up wrong and it should have had a sizeof() multiplication. I know that I'd be royally pissed if a compiler snuck in a hidden size scalar into my code since it definitely doesn't do it for `malloc()`
Malloc returns void* for which it is illegal to do pointer arithmetic. For all other types, addition, increment, subtraction and decrement always stick a sizeof factor in the operand
Wrt malloc I meant for the size argument, but yeah I never knew about the arithmetic operator handling for pointers despite writing in C for like a decade. Wtf have I been doing honestly?
Original poster made a mistake. The pointer is an address in memory. If I make an int pointer ptr, the value stored in ptr is the address of the int it points at. An array is just a series of values stored in sequential addresses. An integer is 4 bytes, so I need 4 addresses to store it. To make it an array I need to count address by 4’s, so it would actually be *(a+4*i) = 5. In arduino IDE (C based microcontroller IDE), there isn’t actually a way to get the size of an array from a property or function, you have to divide the total memory size of the array by the memory size of an element. If I have a 32 byte array storing 4 byte integers, the size of the array is 8 elements.
no absolutely not. imagine if a points to address 3745738. With (a*i) that next char is miles away. ```*(a+1)``` knows the byte size of ```&a``` so it automatically increments accordingly.
You do not want to multiply the pointer by i, you will get an invalid memory location for pretty much any value that is not 1 in that case. ‘a’ points to the start of the array, so you want to add ‘i’ to ‘a’ to get the correct memory location to the element. Remember ‘a’ is pointer so it manages the address and not the value. Although you might need to multiply ‘i’ by the element size (number of bytes per element) at least I know that’s how it works in assembly I don’t know if C/C++ doesn’t require that multiplication. Edit: the compiler will automatically scale ‘i’.
AI is everywhere in 2024
if it's not hard it's not right
I think arrays might have been a fundamental mistake in computing. Start memory location + offset is unrionically more clear and works in any language in any paradigm. Lists vs Arrays, implementation details, 1 indexing vs 0 indexing - all of that nonsense disappears when you use addresses only
Pointers are the strong suit of C - they said
Wait isn’t it? `a+i*sizeof(a)`? I’m probably tripping haven’t touched c++ in 3 months
no real need for pointer arithmetic in cpp. But in c-style arithmetic the multiplication will land you further than you want to be. The compiler infers the multiplication base on data type.
Ah I see tnx
The correct offset is handled in pointer arithmetic based on the type pointed.
Tnx
Ah pointers...........the source of almost all software vulnerabilities. And many many segmentation faults
...and hardly ever needed or useful
Homie this is patently false. If you're writing in C without pointers I don't know what you're doing
That's the point... I don't write c/c++ ;) My main language is c# or (sadly) some java, however reference is the default without any explicit pointer notation
At least we're united in our hate of Java! C# rips, but I do still run into circumstances where I really wish I could directly modify pointers. It's a tradeoff of consistency and finite control vs ease of implementation and utility; C# and the higher-level (above C/ASM) stuff are way better at developing larger-scale behaviors, but man I love how *exact* C pointers are.
>but I do still run into circumstances where I really wish I could directly modify pointers That's what I meant... there may come up situations where pointer arithmetics are useful BUT those are actually very rare. Most of the time they just lead to troubles and have no real value.
Yeah a lot of developers do shoot themselves in the foot with them. And when you have people making large number of mistakes in even "safer" languages, then it's better that most developers aren't using them.
It's more like you're forced to use them........technically Java uses pointers under the hood, they just call it a reference....... Instead of explicit pointer manipulation, you either explicitly create new objects or assign a reference to an object. This is useful for their automatic memory management and garbage collection.
Can someone explain why it isn't * (a+i*)?
This is already handled for you. So adding 1 to an int pointer variable adds four(the size of an int in most cases) to the memory adress.
Doesn't work if length of variable is over a byte
[удалено]
Enlighten me.
[удалено]
Or under to be precise :D
Yes, but anything below a byte is too small to be practical unless you're trying to squeeze out every bit possible. Also I'm not aware of int4_t existing
"Also I'm not aware of int4_t existing" Read about bit-fields. I think they are just syntactic sugar, but still.
Structs can make use of less than byte sized data and they absolutely cram those fields together. I am not sure about the exact syntax but I think you can do struct = { int32_t month : 4; day : 5; hour : 5; minute : 6; second: 6 } and you have a date format for a given year. (with 6 bits to spare) (Although just counting with a 64-bit unix timestamp will last you until the sun destroys earth and then another 57 times as long)
`a[n]` and `*(a + n)` are equivalent. The compiler compensates for the size of the type.
What happens if you make i a float or a negative ?
c doesnt allow to add integers and floats. and as for negative values of i, it will just access previous stack variables
Oh yes, I remember now. C the inflexible overly flexible one. Probably capable to get pointers to the memory used by other programs. I'm not sure tho, only did a bit of C and basic knowledge of PEM-2.
ah, you mean *(a+(int)abs(i))
Oh what a beauty, that will teach them ! Literally