Каковы последствия простой проверки значения указателей в условном выражении?

0

Вот мой код:

#include <iostream>
using namespace std;
int countX(char*, char);

int main() {
    char msg[] = "there are four a in this sentence a a";
    //char *ptr = msg; // <----- question 2!
    cout << countX(msg, 'a');
    cin.get();
}

int countX(char* ptr, char x) {
    int c = 0;
    for (; *ptr; ptr++) {
        if (*ptr == x) c++;
    }
    /*
    while(*ptr) {
        if(*ptr==x) c++;
        ptr++;
    }
    */
    return c;
}

Мне было интересно несколько вещей, касающихся безопасной практики и указателей:

  1. Моя условная инструкция в for-loop ; *ptr ; ; *ptr ; , является ли эта безопасная практика? Будет ли каждый разрыв, если в памяти будет что-то, хранящееся в памяти рядом с последним элементом массива? Возможно ли это? Как он знает, когда прекратить? Когда *ptr считается неприемлемым?
  2. (относительно прокомментированного char *ptr = msg; в основном): я понимаю, что указатель и массив очень схожи, однако есть ли разница между передачей фактического массива в countX и передачей указателя (который указывает на начало массива?).
  3. В countX я countX два разных подхода к простой проблеме. Один считается превосходящим другого?
  • 0
    не используйте необработанный указатель, если вы действительно заботитесь о безопасности. это C ++, а не C. Вы можете использовать std::string и std::count_if
  • 1
    Я нахожусь в фазе обучения, поэтому я просто пытаюсь понять, как все работает, играя с этим. Не обязательно касается безопасности на данном этапе. Просто интересно, что считается хорошей практикой, чтобы я не свернул плохую технику в мою голову так рано.
Показать ещё 2 комментария
Теги:
arrays
pointers
pointer-to-pointer

3 ответа

1

Q Мой условный оператор в for-loop; * ptr; это безопасная практика?

Да, большую часть времени. Подробности смотрите ниже.

Q Будет ли это каждый (я знаю, что вы имели в виду когда-либо), если произойдет что-то, хранящееся в памяти, рядом с последним элементом массива?

A Да.

Q Возможно ли это?

A Да. Вы можете легко получить доступ к памяти за прошлым символом массива и сделать ее чем-то отличным от нулевого символа.

Q Как он знает, когда прекращать работу?

A Он прекратится, когда вы столкнетесь с завершающим нулевым символом строки. Если нулевой символ заменен чем-то другим, поведение будет непредсказуемым.

Q Когда * ptr считается неприемлемым?

A Если длина строки равна len, нормально установить ptr в диапазоне msg и msg+len. Если ptr указывает на что-либо за пределами этого диапазона, поведение не определено. Следовательно, они должны считаться неприемлемыми в программе.

Q (относительно прокомментированного char * ptr = msg; в основном): я понимаю, что указатель и массив очень схожи, однако есть ли разница между передачей фактического массива в countX и передачей указателя (что указывает на начало массива?).

A, N Они идентичны.

Q В countX я предложил два разных подхода к простой проблеме. Один считается превосходящим другого?

Нет, они не являются. Это сводится к личным вкусам. Мне нравится использовать for циклов, в то время как я знаю людей, которые любят использовать в while циклы.

  • 0
    Спасибо за ответ! Быстрый вопрос: Когда вы говорите, чтобы держать ptr в диапазоне msg и msg+len , это потому, что поскольку msg является постоянным указателем на первый элемент, что указывает на начало массива?
  • 0
    @JhomasTefferson Это совершенно верно.
0

Q1: Мой условный оператор в for-loop; * ptr; это безопасная практика? Будет ли каждый разрыв, если в памяти будет что-то, хранящееся в памяти рядом с последним элементом массива? Возможно ли это? Как он знает, когда прекратить? Когда * ptr считается неприемлемым?

Ans: При использовании с строками c-стиля да, это безопасная практика. Любая строка c-style обязательно заканчивается на "\ 0", которая в основном равна 0. Поведение не определено, когда "\ 0" не существует. Таким образом, цикл будет разбит в конце строки. * ptr никогда не прекратится, если это что-то другое, кроме строки c-style. Например, c-style "hello" на самом деле представляет собой массив, содержащий "h", "e", "l", "l", "o", "\ 0". Таким образом, цикл существует в '\ 0', никогда не получая доступ к памяти после него. можно получить доступ к памяти после последнего элемента массива. Например,

int a[5] = {0,1,2,3,4,5};
int *p = a+5;

p обращается к элементу после последнего элемента массива a.

Q2: (относительно прокомментированного char * ptr = msg; в основном): я понимаю, что указатель и массив очень схожи, однако есть ли разница между передачей фактического массива в countX и передачей указателя (который указывает к началу массива?).

Ans: Массивы и указатели не совсем похожи. Его просто то, что имя массива - не что иное, как постоянный указатель, указывающий на первый элемент массива. Рассмотрим предыдущий пример, который я написал. В этом случае [3], 3 [a], * (a + 3) и * (p + 3) все относятся к одному и тому же элементу. Поскольку вы проходите по значению, значение константного указателя msg будет просто скопировано в ptr. Итак, нет, это не имеет значения.

Q3: В countX я предложил два разных подхода к простой проблеме. Один считается превосходящим другого?

Анс: Я не эксперт, но я бы сказал, нет.

Кроме того, вам, вероятно, не нужен cin.get().

  • 0
    Невозможно получить доступ к памяти после последнего элемента массива. В вашем примере p указывает на один конец, что нормально, но не имеет к нему доступа (что было бы неопределенным поведением, если бы вы попытались).
  • 1
    Большое спасибо за ответ! Имя массива, являющееся постоянным указателем на первый элемент, - это то, о чем я раньше не думал. Кроме того, cin.get() поддерживает cmdprompt открытым (до ENTER), так что я могу перехватить результат до его закрытия. Разве есть лучший способ сделать это, о котором я не знаю? Или вы имели в виду по совершенно другой причине? Для Мэтта МакНабба, да, я немного читал о неопределенном поведении, также довольно новом для этого. Переход к C ++ из Java определенно менее ограничен, я уже нашел.
Показать ещё 3 комментария
-2

Это очень плохая практика.

Что вы делаете в условии for в основном, if (*ptr), другими словами, указывает ли память, на которую указывает ptr ненулевое значение?

Поэтому, если ячейка памяти после строки содержит ненулевое значение (возможно, из другой переменной с использованием пробела) или значение мусора, то ваш цикл может быть бесконечным или дать неверное значение. Вместо этого вы должны запустить цикл от 0 до длины строки.

  • 1
    Наоборот, это нормальный и вполне приемлемый C-код при определенных условиях. Такой код будет работать нормально, пока ptr допустим и указывает на массив с нулевым символом в конце. Если это не так, то у вас большие проблемы. В мире Си так все и делается. Обратите внимание, что цикл предназначен для остановки при достижении первого нулевого значения. В C ++ есть более безопасные альтернативы, но даже тогда указатели и итераторы обычно используются способами, которые могут быть такими же хрупкими.
  • 0
    Значит, в этом контексте безопасны массивы (строки)? Разве что-то случается (по какой-то случайности) с перезаписью нулевого терминатора в памяти? (Я предполагаю, что это невозможно, если это не сделано вручную?) Кроме того, простите этот вопрос: int / float / другие типизированные массивы, они также обнуляются? К чему приводит вопрос: все ли массивы обнуляются? Если так, зачем указывать массивы с нулевым символом в конце? Каков пример массива без вышеупомянутого завершения?
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню