Pointers just point to an address in memory. It could point to a single structure or variable, but it also became a standard in C to use pointers to point to the start of an array. When used like this, you have to either agree what the end of an array looks like (e.g. '\00' for end of char array aka string), or manually forward the size of the array to a function, e.g. void do_something(int *numbers, size_t number_count). Accessing elements of the array like numbers[5] is effectively just a nice shorthand for dereferencing (numbers + 5 * sizeof(int)), there is no bounds checking and you can access bad memory with a bad index.
Over time people realized this is kinda dumb and annoying, so now C++ has std::span, Rust has slices, which are basically structures that store both a pointer and a size, so you can define functions like void do_something(std::span<int> numbers). C will remain forever though so we have to forever deal with the above