указатель на массив - PullRequest
       22

указатель на массив

5 голосов
/ 15 декабря 2009

Мне интересно, вы можете сделать указатель на группу переменных в массиве? как это

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

так что тогда вы могли бы сказать ...

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

и

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

и длина * указателя

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

OK

Позвольте мне объяснить, что я пытаюсь сделать, возможно, это немного прояснит меня. Я хочу прочитать полный файл в буфер, но я хочу сделать это по частям. Передача небольшого массива в read (), а затем зацикливание его на большем массиве лишает цели цели. Я надеялся, что смогу напрямую "указать" на область в буфере, который я хочу заполнить, и передать это функции read ().

Я НЕ хочу использовать потоки или что-либо, что буферизируется за моей спиной

это было бы контрпродуктивно, так как я пытаюсь сразу прочитать весь файл в память. Как можно быстрее.

Мне нужна скорость !!!

Ответы [ 10 ]

12 голосов
/ 15 декабря 2009

Несмотря на то, что все говорили, это возможно с одним небольшим предупреждением - если у вас нет компилятора C99, вы должны знать размер «среза», который вы хотите во время компиляции.

Чтобы правильно объявить и использовать указатель, вы также должны знать, что подстрочный оператор [] связывается перед оператором разыменования *, поэтому нужны парантезы.

Вот:

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

Добавление:

Для ответа на вашу актуальную проблему, которую вы поставили, это намного проще. Просто используйте указатель, который установлен на смещение от буферного массива, например:

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] */
6 голосов
/ 15 декабря 2009

Конечно, вы можете.

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

Выход будет 3-4.

4 голосов
/ 15 декабря 2009

Как уже говорили другие, вы можете легко выполнить первую часть. Просто сделай pointer = array + 6. Но что такое pointer? Он не может быть объявлен как:

char pointer[5];

или аналогичный. Это должен быть указатель :

char *pointer = array + 6;

Это потому, что вы не можете присвоить массив какому-либо другому имени (массив не является изменяемым l-значением). Не имеет смысла говорить:

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

Теперь в C размер указателя равен размеру указателя & mdash; так как указатель не имеет понятия "количества единиц" указанного типа. Массивы, с другой стороны, точно знают, сколько у них элементов, и вы можете получить этот размер, применив соответствующий оператор sizeof.

Итак, sizeof array в вашем примере будет 10 (если в нем 10 элементов), тогда как sizeof pointer будет числом байтов, занятым указателем char. Следовательно, то, что вы спрашиваете во второй части вашего вопроса, невозможно в C . В C ++ у вас есть доступ к типам данных, которые должны позволять вам делать то, что вы хотите.

Редактировать : Чтобы прочитать файл кусками:

Допустим, у вас большой буфер, и вы уверены, что можете прочитать весь файл в:

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

Для небуферизованного ввода / вывода посмотрите setvbuf(). Но проверьте буферизованные и небуферизованные входы, чтобы увидеть, какой из них быстрее Проверьте также различные размеры чтения.

Теперь отступ, который я положил раньше, и, думаю, я все равно оставлю это здесь:

Отвечая на этот вопрос, интереснее делать это по-другому , т.е., учитывая:

T a[10];

для любого типа T, можете ли вы объявить pointer таким, что:

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

(или, если вы чувствуете себя авантюрным, замените 1 большим положительным числом в LHS первого утверждения).

Ответ, согласно стандарту C, нет . Как упомянуто в ссылке, Численные рецепты в C использовали этот «трюк».

В сторону, я думаю, вы имели в виду

pointer[0] == array[6];

а не

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

в вашем вопросе (аналогично для *pointer[5])

4 голосов
/ 15 декабря 2009

В приведенном ниже примере я объявил статический массив из 10-кратных целых. Я создал 2 указателя на его элементы - таким образом, определяя диапазон. Затем я объявил в цикле for указатель, начинающийся с указателя p1, который проходил через каждый элемент массива, пока не достиг указателя p2 - значения элемента печати. ​​

Это то, что вы искали?

#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;
}
3 голосов
/ 15 декабря 2009

указатель указывает на одну ячейку памяти, поэтому, как уже говорили другие, вы можете получить указатель, указывающий на местоположение в середине массива

char *p = array + 6;

Вы должны выразить допустимый диапазон другим способом, то есть, передав максимальную длину. или второй указатель

вероятно стоит отметить, что

array[i] 

идентично

*(array + i)
3 голосов
/ 15 декабря 2009

Вы можете иметь указатель, указывающий на любой элемент массива C. Поскольку массивы C не «знают» их длину, идея «диапазона» массива C не может быть выражена напрямую. Как вы должны хранить длину самого массива, так и вы должны хранить длину диапазона, на который указывает указатель.

2 голосов
/ 15 декабря 2009

Да, если вы правильно используете адреса:

int* ptr = new int[10];
int* ptrSub = &ptr[5];
2 голосов
/ 15 декабря 2009

pointer = &array[6]. pointer[0] теперь будет ссылаться на то же значение, что и array[6]. Непосредственно невозможно извлечь ссылку на фрагмент массива и сохранить для него семантику sizeof. Вы можете эмулировать это примерно так:

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);
1 голос
/ 15 декабря 2009

Если я прочитал ваш вопрос, вы хотите обратиться к ряду элементов в исходном массиве, так сказать, куске.

В C ++ вы можете сделать это легко - при условии, что вы реализуете свой собственный класс массива (сохраняя указатель + числовые элементы). Затем вы можете определить функции-члены, которые вернут вам фрагмент: указатель на исходный массив и ряд элементов, которые вы не будете адресовать за пределы исходного массива.

В Plain-Old-C вы не можете изменять размеры массивов, разделяющих хранилище, и указатель не ограничен по определению: он просто указывает на один элемент. Вы не можете позволить C-коду «интерпретировать» размерный массив, поскольку имя массива (символ) - это адрес хранилища, которое вы не можете изменить.

То, что вы хотите, это:

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

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

но это не разрешено. Имя «array2» переводится компилятором в фиксированный адрес, который вы не можете переопределить во время выполнения - вот почему есть указатели: из них вы можете изменить то, на что они указывают по желанию во время выполнения.

0 голосов
/ 15 декабря 2009

Указатели только указывают на первый элемент в любой структуре или переменной. Они только адрес. Вы можете подразумевать диапазон, сделав их указателем на определенный тип, который идентифицирует диапазон.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...