开发者

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 m开发者_JAVA百科emory at once. As fast as possible.

I need speed!!!


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] */


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.


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;
}


As others have said, you can easily do the first part. Just do pointer = array + 6. But what is pointer? It cannot be declared as:

char pointer[5];

or similar. It has to be a pointer:

char *pointer = array + 6;

This is because you can't assign an array to some other name (an array is not a modifiable l-value). It does not make sense to say:

char a[10];
char b[10];
b = a;

Now, in C, the size of a pointer is just the size of the pointer—since a pointer does not have a notion of "the number of units" of a given type pointed to. Arrays, on the other hand, know exactly how many elements they have, and you can get that size by an appropriate use of the sizeof operator.

So, sizeof array in your example would be 10 (if it has 10 elements), whereas sizeof pointer is going to be the number of bytes occupied by a char pointer. Therefore, what you ask in the second part of your question is impossible in C. In C++, you have access to data types that should allow you to do what you want.

Edit: To read a file in chunks:

Let's say you have a big buffer, that you're sure you can read the whole file into:

unsigned char bigbuf[1UL << 24]; /* or whatever you want */
unsigned char *ptr = bigbuf;
size_t chunk = BUFSIZ;
FILE *fp = fopen("foo.txt", "rb"); /* no error checking */
size_t nread;
size_t total = 0;
while ((nread = fread(ptr, 1, chunk, fp)) > 0) {
    ptr += nread;
    total += nread;
    if (total + chunk > sizeof bigbuf) {
        /* oops, not enough space */
    }
}
if (ferror(fp)) {
    /* read error */
} else {
    /* bigbuf now has data, total has the number of bytes */
}

For unbuffered I/O, look at setvbuf(). But test buffered and unbuffered inputs to see which one is faster. Test different read sizes too.

Now an aside, which I had put in before, and I guess I will leave it in here anyway:

Having answered this question, more interesting is doing it the other way, i.e., given:

T a[10];

for any type T, can you declare pointer such that:

pointer[1] == a[0]
pointer[2] == a[1]
...
pointer[11] == a[10]

(or if you're feeling adventurous, replace 1 by a bigger positive number on the LHS of the first statement).

The answer, according to the C standard, is no. As mentioned in the link, Numerical Recipes in C made use of this 'trick'.

As an aside, I think you meant

pointer[0] == array[6];

and not

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

in your question (similarly for *pointer[5])


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.


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)


Yes, if you use the addresses correctly:

int* ptr = new int[10];
int* ptrSub = &ptr[5];


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);


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜