Адресная арифметика с указателями [закрывается]

Возможность чтения локального файла из вашего браузера будет серьезным нарушением безопасности - мне не нравится идея того, что какой-либо сайт, который я посещаю, может запускать код в моем браузере, который будет читать файлы с моего жесткого диска , Обычно запросы ajax ограничиваются доменом, из которого была создана страница. (Тем не менее, вы можете обойти это в некоторой степени с помощью таких методов, как JSONP.) Большинство браузеров не позволят вам читать локальные файлы, даже если страница возникла из вашей локальной файловой системы.

Другие упомянутые методы должны позволять вам для чтения файлов из домена (даже если это localhost), но не из вашей файловой системы напрямую.

58
задан starblue 17 February 2009 в 20:26
поделиться

6 ответов

Во-первых, видео binky может помочь. Это - хорошее видео об указателях. Для арифметики вот пример:

int * pa = NULL;
int * pb = NULL;
pa += 1; // pa++. behind the scenes, add sizeof(int) bytes
assert((pa - pb) == 1);

print_out(pa); // possibly outputs 0x4
print_out(pb); // possibly outputs 0x0 (if NULL is actually bit-wise 0x0)

(Отмечают, что постепенное увеличение указателя, который содержит значение нулевого указателя строго, является неопределенным поведением. Мы использовали ПУСТОЙ УКАЗАТЕЛЬ, потому что мы только интересовались значением указателя. Обычно, только используйте инкремент/декремент когда указывающий на элементы массива).

следующие шоу два важных понятия

  • дополнение/вычитание целого числа к средству указателя перемещают указатель вперед / назад элементами N. Таким образом, если интервал составляет большие 4 байта, pa мог бы содержать 0x4 на нашей платформе, увеличив 1.
  • вычитание указателя другим указателем означает получать их расстояние, измеренное элементами. Так вычитание свинца от pa уступит 1, так как у них есть одно расстояние элемента.

На практическом примере. Предположим, что Вы пишете функцию, и люди предоставляют Вам запуск и указатель конца (очень общая вещь в C++):

void mutate_them(int *begin, int *end) {
    // get the amount of elements
    ptrdiff_t n = end - begin;
    // allocate space for n elements to do something...
    // then iterate. increment begin until it hits end
    while(begin != end) {
        // do something
        begin++;
    }
}

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

52
ответ дан Johannes Schaub - litb 7 November 2019 в 15:21
поделиться

Вот то, где я изучил указатели: http://www.cplusplus.com/doc/tutorial/pointers.html

, Как только Вы понимаете указатели, адресная арифметика с указателями легка. Единственная разница между ним и регулярной арифметикой - то, что число, которое Вы добавляете к указателю, будет умножено на размер типа, на который указывает указатель. Например, если у Вас есть указатель на int и int, размер составляет 4 байта, (pointer_to_int + 4) оценит к адресу памяти 16 байтов (4 ints) вперед.

Поэтому то, когда Вы пишете

(a_pointer + a_number)

в адресной арифметике с указателями, что действительно происходит,

(a_pointer + (a_number * sizeof(*a_pointer)))

в регулярной арифметике.

58
ответ дан Jeremy Ruten 7 November 2019 в 15:21
поделиться

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

то, когда обучающие указатели, способность продолжает о "p, является указателем на a, значение p является адресом" и так далее. это просто работа привычки. вот сырье для Вас для создания с. практика с ним и Ваши студенты получат его.

'интервал', целого числа, это хранит значения целого типа. 'интервал* p', p является 'международной звездой', он хранит 'международные звездообразные' значения типа.

, как Вы получаете, 'какое' целое число, сохраненное в (пытаются не использовать 'значение'), '&' то, как Вы добираетесь, 'где' самостоятельно хранится (попытайтесь сказать 'адрес')

'b =' для этого для работы обе стороны должны иметь тот же тип. если интервал, b должен быть способен к хранению интервала (так ______ b, пробел заполнен 'интервалом')

'p = &' для этого для работы обе стороны должны иметь тот же тип. если целого числа, & адреса, p должен быть способен к хранению адресов целых чисел. (так ______ p, пробел заполнен 'интервалом * ')

теперь интервал записи *p по-другому для вывода наружу информации о типе:

интервал* | p

, что такое 'p'? ответ: это - 'интервал *'. таким образом, 'p' является адресом целого числа.

интервал | *p

, что такое '*p'? ответ: это - 'интервал', таким образом, '*p' целое число.

теперь на адресной арифметике:

интервал a; a=1; a=a+1;

, что мы делаем в 'a=a+1'? думайте о нем как 'затем'. Поскольку числа, это похоже на высказывание 'следующее число'. Начиная с хранения 1, говоря 'затем' сделают его 2.

//ошибочный пример. Вас предупредили!!! интервал *p интервал a; p = &a; p=p+1;

, что мы делаем в 'p=p+1'? это все еще говорит 'затем'. На этот раз p не является числом, а адресом. Таким образом, то, что мы говорим, является 'следующим адресом'. Следующий адрес зависит от типа данных, более конкретно от размера типа данных.

printf (" %d %d %d", sizeof (символ), sizeof (интервал), sizeof (плавание));

поэтому 'затем' для адреса продвинется sizeof (тип данных).

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

6
ответ дан 7 November 2019 в 15:21
поделиться

Я считаю хороший пример адресной арифметики с указателями следующей функцией длины строки:

int length(char *s)
{
   char *str = s;
   while(*str++);
   return str - s;
}
3
ответ дан arul 7 November 2019 в 15:21
поделиться

Так, ключевая вещь помнить состоит в том, что указатель является просто переменной размера слова, это вводится для разыменования. Это означает, что, является ли это пустотой *, интервал *, долго долго **, это - все еще просто измеренная переменная слова. Различие между этими типами - то, что компилятор рассматривает разыменованным типом. Просто для уточнения слово измерило ширину средств виртуального адреса. Если Вы не знаете то, что это означает, просто помните на 64-разрядной машине, указатели составляют 8 байтов, и на 32-разрядной машине, указатели составляют 4 байта. Понятие адреса СУПЕР важно в понимании указателей. Адрес является числом, способным к однозначному определению определенного местоположения в памяти. Все в памяти имеет адрес. В наших целях мы можем сказать, что каждая переменная имеет адрес. Это не обязательно всегда верно, но компилятор позволяет нам принять это. Сам адрес является детализированным байтом, означать 0x0000000 определяет начало памяти, и 0x00000001 составляет один байт в память. Это означает, что путем добавления одного к указателю, мы перемещаем один байт вперед в память. Теперь, позволяет, берут массивы. Если Вы создаете массив типа quux, это - 32 большие элемента, он охватит с начала, он - выделение, к началу он - выделение плюс 32*sizeof (quux), так как каждая ячейка массива является sizeof (quux) большой. Так, действительно когда мы определяем элемент массива с массивом [n], это - просто синтаксический сахар (стенография) для * (array+sizeof (quux) *n). Адресная арифметика с указателями действительно просто изменяет адрес, к которому Вы обращаетесь, который является, почему мы можем реализовать strlen с

while(*n++ != '\0'){
  len++;
}

, так как мы просто сканируем вперед, байт байтом, пока мы не поражаем нуль. Надежда, которая помогает!

1
ответ дан 7 November 2019 в 15:21
поделиться

Существует несколько способов заняться им.

интуитивный подход, который является тем, о чем думает большинство программистов C/C++, состоит в том, что указатели являются адресами памяти. пример litb проявляет этот подход. Если у Вас есть нулевой указатель (который на большинстве машин соответствует адресу 0), и Вы добавляете размер интервала, Вы получаете адрес 4. Это подразумевает, что указатели являются в основном просто необычными целыми числами.

, К сожалению, существует несколько проблем с этим. Для начала это не может работать. Нулевой указатель, как гарантируют, на самом деле не будет использовать адрес 0. (Хотя присвоение постоянного 0 к указателю приводит к нулевому указателю).

Далее, Нельзя увеличить нулевого указателя, или в более общем плане, указатель должен всегда указывать на выделенную память (или один элемент мимо), или специальный нулевой указатель постоянный 0.

, Таким образом, более корректный образ мыслей его - то, что указатели являются просто итераторами, разрешающими Вам выполнить итерации по выделенной памяти. Это - действительно одна из ключевых идей позади итераторов STL. Они смоделированы, чтобы вести себя очень как указатели и обеспечить специализации, которые исправляют необработанные указатели для работы надлежащими итераторами.

А более тщательно продуманное объяснение этого дано здесь , например.

, Но это последнее представление означает, что необходимо действительно объяснить итераторы STL, и затем просто сказать, что указатели являются особым случаем их. Можно увеличить указатель для указания на следующий элемент в буфере, точно так же, как Вы можете std::vector<int>::iterator. Это может указать на один элемент мимо конца массива, точно так же, как конечный итератор в любом другом контейнере. Можно вычесть два указателя , что точка в тот же буфер для получения числа элементов между ними, точно так же, как Вы можете с итераторами, и точно так же, как с итераторами, если указатели указывают в отдельные буферы, Вы можете не , обоснованно сравнивают их. (Для практического примера почему не, рассмотрите то, что происходит в сегментированном пространстве памяти. Каково расстояние между двумя указателями, указывающими для разделения сегментов?)

, Конечно, на практике, существует очень близкая корреляция между адресами ЦП и указателями C/C++. Но они не точно то же самое. Указатели имеют несколько ограничений, которые не могут быть строго необходимыми на Вашем ЦП.

, Конечно, большинство программистов на C++ запутывает на первом понимании, даже при том, что это технически неправильно. Это достаточно обычно близко к тому, как Ваш код заканчивает тем, что вел себя, что люди думают, что получают его и идут дальше.

, Но для кого-то происходящего из Java, и просто узнающий об указателях с нуля, последнее объяснение может быть столь же понятным, и это собирается преподнести меньше сюрпризов на них позже.

0
ответ дан jalf 7 November 2019 в 15:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: