views:

325

answers:

10
+1  Q: 

pointer to array

I'm wondering, can you make a pointer to a group of variables in an array? like this

array[20]{'a','b','c',...}
pointer = array[6 through 10];

so then you could say...

*pointer[0] == array[6];

and

*pointer[5] == array[10];

and the length of *pointer

5 == sizeof(*pointer) \ sizeof(type);

OK

Let me explain what I'm trying to accomplish, maybe that will clear me up a bit. I want to read a full file into a buffer, but I want to do it piece by piece. passing a small array into read() and then looping it into the larger array defeats the purpose. I was hoping that I could directly 'point' to an area in the buffer I want to fill, and pass that to the read() function.

I DO NOT want to use streams or anything that buffers behind my back

that would be counterproductive as I'm trying read the whole file into memory at once. As fast as possible.

I need speed!!!

+1  A: 

pointer = &array[6]. pointer[0] will now reference the same value as array[6]. It's not directly possible to extract a reference to a slice of an array and keep sizeof semantics for it. You can emulate it with something like this:

template <class T>
class Slice {
public:
 Slice(T* elements, int begin, int end) : m_elements(elements + begin), m_size(end - begin) {}
 T& operator[] (int index) {return m_elements[index];}
 int size() const {return m_size;}
private:
 T* m_elements;
 int m_size; 
};

int values[10];
Slice<int> slice(values, 5, 10);
values[5] = 3;
assert(slice[0] == values[5]);
assert(slice.size() == 5);
Andreas Brinck
+6  A: 

Sure enough you can.

int a[4] = {1,2,3,4};
int *b = &a[2];
cout << b[0] << "-" << b[1] << endl;

The output will be 3-4.

Frank
jk
+1  A: 

Yes, if you use the addresses correctly:

int* ptr = new int[10];
int* ptrSub = &ptr[5];
Cecil Has a Name
+2  A: 

You can have a pointer pointing to any element of a C array. Since C arrays do not "know" their length, the idea of a "range" of a C array cannot be expressed directly. As you have to store the length of the array itself, so you have to store the length of the range the pointer points to.

sbi
C arrays *do* know their length. That is why I can do: int a[] = { 1, 2, 3}; sizeof a / sizeof a[0]; and get 3.
Alok
@Alok: But you can't write a function that takes arrays of different sizes, without passing the size explicitly.
unwind
@ Alok: Only if specified at compile time...
DevSolar
int function(char * a, int *b){ return sizeof(a) \ sizeof(char);}
kelton52
or you could use malloc(randomsize)
kelton52
@DevSolar, yes, I am not talking about VLAs. @unwind, when you pass an array to a function, it "decays" to a pointer, and is no longer an array. In other words, the function only sees the pointer to the first element of the array. @kelton, your "function" will always return the size of a char * pointer.
Alok
@kelton, that won't work. You're just going to get back the size of the pointer in bytes. You can only use the sizeof(arr)/sizeof(arr[0]) in the same scope that you declared arr (ie you can't take it as a parameter).
Graphics Noob
Just to add a little more noise into the discussion: In C you cannot, in C++ you can: `void f( int (` will take only arrays of 10 integer elements. If you move the 10 into a template argument then you have a function (family of functions thereof) that will take arrays with a known size. This is used to obtain the size of an array: `template <typename T, std::size_t N> std::size_t array_size( T ( }` and can be further tweaked into providing a compile time constant if needed.
David Rodríguez - dribeas
@dribeas: thanks for the info!
Alok
A: 

Pointers only 'point' to the first item in any structure or variable. They are only an address. You could imply a range by making them a pointer to a specific type which identifies a range.

Tony Lambert
so basicallyface somearray[6];typedef face miniarray;miniarray *a =
kelton52
extactly.... not sure why someone marked me down?
Tony Lambert
+2  A: 

In the below example I've declared a static array of 10x ints. I've created 2 pointers to it's elements - thus defining a range. What I did next was : I declared a pointer in the for loop starting with the pointer p1 which went through every item in the array until it reached pointer p2 - printing item's value.

Is that what you were looking for?

#include <iostream>
using namespace std;

int main()
{ 
    int a[10] = { 0, 4, 5, 7, 4, 3, 1, 6, 2, 9 };

    int *p1 = &a[3];
    int *p2 = &a[7];

    for(int *p = p1; p != p2; ++p)
    {
     cout << *p << endl;
    }

    return 0;
}
Maciek
Chris, you're mistaken. That code is fine.
caf
Chris Lutz
+2  A: 

a pointer points to a single memory location, so while, as others have said you can get a pointer to point to a location in the middle of an array

char *p = array + 6;

you need to express the allowed range some other way i.e. by passing a max length. or a second pointer

its probably worth pointing out that

array[i]

is identical to

*(array + i)
jk
+3  A: 
Alok
A: 

If I read your question you want to address a range of elements in the original array, a slice so to say.

In C++ you can do that easily - provided you implement your own arrayclass (keeping a pointer + number elements). Then you can define memberfunctions which will give you back a slice: a pointer into the original array and a number of elements such that you will not address outside the original array.

In Plain-Old-C you cannot have to sized arrays sharing storage and a pointer is unbounded by definition: it just points at a single element. You cannot let the C-code "re-interpret" a sized array since the name of the array (the symbol) is the address of the storage, which you cannot modify.

What you want is this:

int  array1[10];
int  array2[3];

// reference 3 elements from array1, starting at element 5 in array1
array2 = array1[5];

but that is not allowed. The name "array2" is translated by the compiler into a fixed address which you cannot redefine at runtime - that's why there are pointers: of those you can change whatever they point to at will at runtime.

haavee
+4  A: 

Despite what everyone has said, this is possible, with one small caveat - unless you have a C99 compiler, you have to know the size of the "slice" that you want at compile time.

To declare and use the pointer correctly, you also have to know that the subscript operator [] binds before the * dereference operator, so parantheses are needed.

Behold:

int array[20] = {'a','b','c','d','e','f','g','h','i','j','k','l'};
int (*pointer)[10 - 6 + 1] = (int (*)[10 - 6 + 1])&array[6];    /* = array[6 through 10] */

printf("(*pointer)[0] = %c\n", (*pointer)[0]);
printf("(*pointer)[4] = %c\n", (*pointer)[4]);
printf("sizeof *pointer / sizeof **pointer = %lu\n", (unsigned long)(sizeof *pointer / sizeof **pointer));

Addendum:

For the answer to your actual problem that you've put in, that's a lot easier. Just use a pointer that is set to an offset from the buffer array, eg:

unsigned char buffer[102400];
unsigned char *ptr;

/* ... */
ptr = buffer + 500;
read(fd, ptr, 1024); /* Try and read up to 1024 bytes at position buffer[500] */
caf
I most defiantly know the 'slice', it never changes. This may be what I was looking for.
kelton52
I'm wrong again. Perhaps this just isn't my day...
Chris Lutz
Nice answer! C99's `(T (*)[N]) a` idiom is useful, thanks. +1.
Alok
oh wow...Can't believe I didn't think of that heh
kelton52
The above snippet is even valid C89 (because `10 - 6 + 1` is a compile-time constant) - you'd need C99 if the `10` and/or the `6` were obtained from variables, though.
caf
OK, I need some sleep. Thanks!
Alok
caf: can you quote the standard where it says this is valid? I think it's implementation defined.
Alok
As far as I can see, the relevant parts are 6.2.5 p20 (where an array type is a *contiguously allocated nonempty set of objects* - padding is not allowed) and 6.3.2.3 p7 (where a pointer must point to the lowest addressed byte of the object). That is, it works for the reason that both `sizeof a / sizeof a[0]` give the number of elements in an array, and that `int (*a)[10] = malloc(20 * sizeof *a);` gives a valid pointer.
caf
But `pointer` is a pointer to "array[5] of int", whereas `array+6` is of type `int *`. 6.3.2.3p7 says, "When a pointer to an object is converted to a pointer to a *character* type, the result points to the lowest addressed byte of the object." `int (*)[5]` is not a pointer to a character object. The same section, previous two lines say: "If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer." I am not sure if `int (*)[5]` is correctly aligned.
Alok
...and even if it is, *...when converted back again, ...* part only says that the converted pointer must compare equal, nothing about dereferencing them.
Alok