Действительно ли возврат является указателем на статическую безопасную локальную переменную?

Вот еще один способ перетасовать список

public List<Integer> shuffleArray(List<Integer> a) {
List<Integer> b = new ArrayList<Integer>();
    while (a.size() != 0) {
        int arrayIndex = (int) (Math.random() * (a.size()));
        b.add(a.get(arrayIndex));
        a.remove(a.get(arrayIndex));
    }
    return b;
}

Выберите случайное число из исходного списка и сохраните его в другом списке. Затем удалите номер из исходного списка. Размер исходного списка будет продолжать уменьшаться на единицу, пока все элементы не будут перемещены в новый список.

41
задан John Carter 18 January 2009 в 21:54
поделиться

6 ответов

Первый пример: Несколько безопасный

char* const GetString()
{
  static char sTest[5];
  strcpy(sTest, "Test");
  return sTest;
}

, Хотя не рекомендуемый, это безопасно, объем статической переменной остается живым, даже когда объем функции заканчивается. Эта функция не очень ориентирована на многопотоковое исполнение вообще. Лучшая функция заставила бы Вас передавать char* buffer и maxsize для эти GetString() функция для заполнения.

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

Второй пример: Абсолютно небезопасный

char* const GetString()
{
  return "Test";
}

Это было бы безопасно, если бы Вы сделали const char *. То, что Вы дали, не безопасно. Причина состоит в том, потому что строковые литералы могут быть сохранены в сегменте постоянной памяти, и разрешение им быть измененным вызовет неопределенные результаты.

char* const (указатель константы) означает, что Вы не можете изменить адрес, на который указывает указатель. const char * (указатель на константу) означает, что Вы не можете изменить элементы, на которые указывает этот указатель.

Заключение:

необходимо рассмотреть также:

1), Если у Вас есть доступ к коду тогда, изменяют GetString для взятия параметра char* buffer для заполнения и maxsize для использования.

2), Если у Вас нет доступа к коду, но необходимо назвать его, обернуть этот метод в другую функцию, которая защищена взаимным исключением. Новый метод как описан в 1.

37
ответ дан artm 23 September 2019 в 15:30
поделиться

Существенно, да, это безопасно в том смысле, что значение продлится неограниченно долго, потому что это статично.

Это не безопасно в том смысле, что Вы возвратили постоянный указатель на переменные данные, а не переменный указатель на постоянные данные. Лучше, если функциям вызова не позволяют изменить данные:

const char *GetString(void)
{
    static char sTest[5];
    strncpy(sTest, "Test", sizeof(sTest)-1);
    sTest[sizeof(sTest)-1] = '\0';
    return sTest;
}

В простом показанном случае, едва необходимо волноваться о переполнении буфера, хотя моя версия кода действительно волнуется и гарантирует пустое завершение. Альтернатива должна была бы использовать функция TR24731 strcpy_s вместо этого:

const char *GetString(void)
{
    static char sTest[5];
    strcpy_s(sTest, sizeof(sTest), "Test");
    return sTest;
}

, Что еще более важно, оба варианта возвращают (переменный) указатель на постоянные данные, таким образом, пользователь не должен идти, изменяя строку и (вероятно) растаптывая вне диапазона массива. (Как @strager указывает в комментариях, возвращение const char * не является гарантией, что пользователь не попытается изменить возвращенные данные. Однако они должны бросить возвращенный указатель, таким образом, это - неконстанта, и затем измените данные; это вызывает неопределенное поведение, и что-либо возможно в той точке.)

Одно преимущество литерального возврата состоит в том, что обещание без записей может обычно осуществляться компилятором и операционной системой. Строка будет помещена в текст (код) сегмент программы, и операционная система генерирует отказ (нарушение сегментации на Unix), если пользователь попытается изменить данные, на которые указывает возвращаемое значение.

[По крайней мере один из других ответов отмечает, что код не повторно используем; это корректно. Версия, возвращая литерал повторно используема. Если повторная входимость важна, интерфейс должен быть зафиксирован так, чтобы вызывающая сторона обеспечила пространство, где данные хранятся.]

9
ответ дан Community 23 September 2019 в 15:30
поделиться

Да, это совершенно безопасно. Время жизни локальных помех является временем жизни всего выполнения программы в C. Таким образом, можно возвратить указатель на него, так как массив будет жив даже после того, как функциональные возвраты и возвращенный указатель могут законно разыменованный.

2
ответ дан Johannes Schaub - litb 23 September 2019 в 15:30
поделиться

static переменные (в функции) как ограниченные по объему глобальные переменные. В целом их нужно избежать (как глобальные переменные, они вызывают проблемы повторной входимости), но время от времени полезны (некоторые стандартные библиотечные функции используют их). Можно возвратить указатели на глобальные переменные, таким образом, можно возвратить указатели на static переменные также.

8
ответ дан strager 23 September 2019 в 15:30
поделиться

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

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

fprintf(stderr, "Error was %s\n", my_string_to_error(error_code));

, Если бы my_string_to_error() возвратил выделенную строку, Ваша программа просочилась бы данный вышеупомянутое (очень) общее использование такой функции.

char const *foo_error(...)
{
    return "Mary Poppins";
}

... также в порядке, некоторые глупые компиляторы могли бы хотеть, чтобы Вы бросили его все же.

Просто строки часов этим способом, не возвращайте книгу:)

0
ответ дан Jonathan Leffler 23 September 2019 в 15:30
поделиться

Это зависит от того, под чем Вы подразумеваете безопасный. Существует несколько проблем, которые я сразу вижу:

  1. Вы возвратились char * const, который позволит вызывающим сторонам менять струну в этом местоположении. Потенциальное переполнение буфера. Или Вы имели в виду const char *?
  2. у Вас могла бы быть проблема с повторной входимостью, или с параллелизмом.

Для объяснения второго рассмотрите это:

const char * const format_error_message(int err)
{
    static char error_message[MAXLEN_ERROR_MESSAGE];
    sprintf(error_message, "Error %#x occurred", err);
    return error_message;
}

, Если Вы называете его как это:

int a = do_something();
int b = do_something_else();

if (a != 0 && b != 0)
{
    fprintf(stderr,
        "do_something failed (%s) AND do_something_else failed (%s)\n",
        format_error_message(a), format_error_message(b));
} 

..., что будет печатным?

То же для поточной обработки.

8
ответ дан Roger Lipscombe 23 September 2019 в 15:30
поделиться
Другие вопросы по тегам:

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