функции возвращая символьный указатель

Я столкнулся с партией функций, возвратив символьные указатели в одном унаследованном приложении. Некоторые из них возвращающий указатели на локальные символьные массивы. Это, кажется, вызывает катастрофические отказы после нескольких вызовов (не сразу!) посмотрите использование ниже

char *f1(){
  char buff[20];
  char *ptr;

  ----
  ----
  ptr=buff;
 return ptr;
}

---
---

f2(f1());

f1 () возвращает локальную переменную указателя и затем передает ее другой функции. Я получил катастрофический отказ непосредственно, когда он скомпилировал использование _DEBUG режим в MS DEV. Но в режиме выпуска, это не вызывает непосредственный катастрофический отказ, но это могло бы произойти после создания большого количества таких вызовов.

Когда я изменил использование как ниже, оно работает без любых проблем. Действительно ли следующее использование безопасно?

strcpy(arr,f1()); /* arr is fixed char array*/
f2(arr);
5
задан cobp 26 February 2010 в 12:42
поделиться

12 ответов

Нет, это неопределенное поведение. Это просто работает в вашем случае, но может перестать работать в любой момент.

12
ответ дан 18 December 2019 в 05:55
поделиться

Безопасно ли следующее использование?

Нет.

Если ваша функция возвращает указатель на что-либо, убедитесь, что она выделяет область памяти и возвращает указатель на нее:

char *safe_f1(void) {
    char *ptr;
    ptr = (char *) malloc(20 * sizeof(char));
    ...
    return ptr;
}
2
ответ дан 18 December 2019 в 05:55
поделиться

Я бы предложил два возможных решения:

  1. Используйте статический char buff [20] в f1 , если функция не вызывается из нескольких потоков или внешний мир не сохраняет указатель за пределами strcpy.

  2. Используйте return strdup (ptr); и free указатель вне f1 . Это проще в использовании, чем malloc (хотя технически то же самое). Он медленнее, чем 1., но потокобезопасен.

0
ответ дан 18 December 2019 в 05:55
поделиться

Нет, это небезопасно. Только вызов strcpy может изменить стек достаточно, чтобы впоследствии вызвать проблемы, поскольку возвращаемый адрес и параметры могут перезаписать массив.

-121--4548566-

Функция f1 возвращает временный (buff), который освобождается при возврате функции. Внутри функции необходимо использовать malloc ().

-121--4548569-

Нет.. все еще небезопасно.

В момент выполнения strcpy (arr, f1 ()); указатель, используемый в качестве второго аргумента, уже указывает на несуществующий массив.

1
ответ дан 18 December 2019 в 05:55
поделиться

Нет, это небезопасно. Просто вызов strcpy может изменить стек настолько, что впоследствии возникнут проблемы, поскольку адрес возврата и параметры могут перезаписать массив.

3
ответ дан 18 December 2019 в 05:55
поделиться

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

3
ответ дан 18 December 2019 в 05:55
поделиться

Функция f1 возвращает временную память (buff), которая освобождается при возврате функции. Необходимо использовать malloc() внутри функции.

2
ответ дан 18 December 2019 в 05:55
поделиться

Никогда не возвращать указатель на локальную переменную. Это может сработать в некоторых ситуациях, но в целом у вас будет много проблем с этим. Вместо этого:

  • задокументируйте свою функцию, что она возвращает указатель на выделенную память и что возвращаемый буфер должен быть освобожден с помощью вызывающий
  • добавляет буфер и аргумент размера и заполняет буфер (это то, что обычно делается в Win32 API)
  • при использовании C ++ используйте std :: string
2
ответ дан 18 December 2019 в 05:55
поделиться

Нет, видите ли, buff[20] доступен только внутри функции f1. Точнее говоря, память выделяется на стеке f1.

Вам нужно создать новый buff[20] на куче с помощью malloc и вернуть указатель на эту память внутри f1. Другой способ - создать buff[20] вне f1 (из функции, которая вызывает f1) и отправить его в качестве аргумента в f1. f1может затем изменить содержимое буфера и даже не обязательно возвращать его.

1
ответ дан 18 December 2019 в 05:55
поделиться

На самом деле, лучше всего было бы изменить f1 () для использования malloc (). Ваше решение не соответствует определенному поведению.

0
ответ дан 18 December 2019 в 05:55
поделиться

Это небезопасно. Причина проста:

Любая переменная в функции будет выделена на стеке, память которого освобождается после возвращения функции. Тот факт, что память освобождается, не означает, что ее содержимое изменяется.

Это означает, что содержимое памяти, которое вы поместили в переменную char buff[20], по-прежнему находится в позиции памяти buff или ptr (поскольку ptr=buff). При вызове другой функции (или выполнении другого блока) переменные функции/блока также попадают в стек, что создает возможность изменения содержимого памяти, на которую указывает позиция ptr.

В примере strcpy, который вы написали, вам повезло, что переменные функции strcpy не попали в стек в позиции, которая находилась внутри старого массива buff. Именно по этой причине у вас сложилось впечатление, что это было безопасно.

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

Решением является использование malloc, потому что malloc выделяет память не на стеке, а на куче. Память кучи не деаллоцируется, пока вы не решите это сделать (вызовом free).

Такой подход гарантирует, что память, на которую указывает ptr, безопасна для использования любой другой функцией.

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

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

PS.: Я думаю, что это безопасно (если ваша программа однопоточная), хотя я не рекомендую делать что-то подобное:

{
  char safe_buffer[20];
  char *unsafe_ptr;
  int i;
  unsafe_ptr = f1();
  /*Copy the buffer without calling any function
    not to change the stack content
  */
  for(i=0;i<20 && *(unsafe_ptr + i) != 0;i++)
  {
    *(safe_buffer + i) = *(unsafe_ptr + i);
  }
  *(safe_buffer + i) = 0;
  f2(safe_buffer);
}
2
ответ дан 18 December 2019 в 05:55
поделиться

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

void f1(char *)

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

0
ответ дан 18 December 2019 в 05:55
поделиться
Другие вопросы по тегам:

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