Member 14798802 Ответов: 5

Как я исправил функцию [warning], возвращающую адрес локальной переменной [-weturn-local-addr] , предупреждение находится на return set3;


// для объединения двух массивов
int* uni(int len1, int len2, int set1[], int set2[])
{
	int set3[20], i, j, k, flag;

	k = 0; 
	
	// Copies the elements of the first set to  new set
	for (i = 0; i < len1;i++)
	{
		set3[k] = set1[i];
		k++;
	}
	
	for (i = 0; i < len2; i++)
	{
		flag=1;

		//Combines the sets 1 and 2
		for (j = 0;j < len1; j++)
			if(set2[i]==set1[j])
			{
				flag=0;
				break;
			}
		
			if(flag==1)
			{
				set3[k]=set2[i];
				k++;
			}
	}	
	
	return set3;
}


Что я уже пробовал:

я попытался сделать это как return set3[20] , тогда он говорит, что [warning] return делает целое число из Указателя без приведения

5 Ответов

Рейтинг:
2

OriginalGriff

Просто чтобы добавить к ответу Грега - который является правильным - я просто кратко объясню, почему это проблема.

Существует два типа памяти, доступной для вашего приложения: куча и стек.
Куча большая - потенциально размер вашей оперативной памяти плюс свободное место на жестком диске, и создается с использованием либо malloc, либо new (предпочтительно последнего). Это используется для большинства ваших данных.
Стек невелик - обычно около 1 МБ - и он выделяется "за кулисами" при вызове функции. Когда вы это делаете, адрес, к которому должна вернуться программа, помещается в стек, и для каждой локальной переменной в вашей функции выделяется место. Когда вы возвращаетесь из функции, это пространство стека освобождается, и обратный адрес выскакивает, тогда программа продолжает работу с инструкцией после вызова. Каждый раз, когда вы вызываете функцию, вы получаете новый набор локальных переменных и новый адрес возврата. Если вы подумаете об этом, то это единственный способ, которым iot может работать, потому что в противном случае рекурсивные вызовы функций вообще не будут работать!

Проблема в том, что iot означает, что все локальные переменные являются временными: они "перестают существовать", когда функция перестает выполняться. И это прекрасно ... если только вы не вернете указатель на один из них ...
Тогда указатель будет в порядке, ваш код будет работать, но как только вы вызовете другую функцию, память, на которую он указывает, будет повторно использована, и ваши значения будут перезаписаны. Этот указатель называется "висячая ссылка", и компилятор, к счастью, достаточно умен, чтобы обнаружить их и предупредить вас, чтобы вы не получили некоторые действительно трудные для отслеживания ошибки, ползущие позже!

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


Рейтинг:
2

KarstenK

Самый простой способ-сделать ваш результирующий массив входным параметром

void uni(int len1, int len2, int set1[], int set2[], int set3[])

совет: переименуйте параметры и переменные в более говорящие имена

бонус: вы также можете использовать ссылочный синтаксис (&-оператор).


Рейтинг:
1

Greg Utas

Есть различные способы исправить это:

1. Сделайте int3 глобальная переменная. Обычно это наименее привлекательное решение.
2. Сделайте int3 переменная в вызываемой функции uni, и передать его в uni в качестве аргумента. Это нормально, если int3 требуется только в вызывающей функции.
3. Сделайте int3 переменная-член класса, который вызывает uni, и передать его в uni в качестве аргумента. Это будет сделано, если класс должен использовать uni позже.
4. Выделить int3 из кучи, используя new Это можно было бы сделать с помощью uni или с помощью функций, которые его вызывают. Когда int3 больше не требуется, освободите его с помощью delete. Если вы используете C++11 или более позднюю версию, то лучше поставить int3 в unique_ptr с помощью make_unique, после чего его можно освободить с помощью unique_ptr::reset В большинстве случаев, uni (даже если завернутый в unique_ptr) все равно был бы членом какого-то класса, и в этом случае int3 будет автоматически освобожден, когда класс будет удален. Или если бы unique_ptr является локальным для функции, int3 будет автоматически освобожден, когда функция вернется.


Member 14798802

я вижу спасибо

Greg Utas

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

Рейтинг:
0

Patrice T

Цитата:
Как я исправил функцию [warning], возвращающую адрес локальной переменной [-weturn-local-addr] , предупреждение находится на return set3

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

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


Рейтинг:
0

CPallini

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

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

int * uni(int set1[], size_t size1, int set2[], size_t size2, size_t * psizer);

int main()
{ 
  int set1[] = {3, 5, 6,-1, 42, 28};
  int set2[] = {100, 5, -23, 42,18};
  
  size_t size1 = sizeof(set1) /sizeof(set1[0]);
  size_t size2 = sizeof(set2) /sizeof(set2[0]);
  
  int * set3;
  size_t size3;
  
  set3 =  uni(set1, size1, set2, size2, &size3);
  
  if ( set3 )
  { 
    for (size_t i = 0; i<size3; ++i)
      printf("%d ", set3[i]);
    printf("\n");
    free(set3);
  }
  return 0;
}

int * uni(int set1[], size_t size1, int set2[], size_t size2, size_t * psizer)
{ 
  assert( set1 &&  set2 && psizer);
  int * setr = (int * ) malloc( (size1+size2) * sizeof(setr[0]));
  if ( ! setr ) return NULL;
  
  memcpy( setr, set1, size1 * sizeof(set1[0]));
  *psizer = size1;
  
  for (size_t i = 0; i<size2; ++i)
  { 
    size_t j; 
    for (j=0; j<size1; ++j)
    { 
      if (set2[i] == set1[j])
        break;
    }
    if ( j == size1 )
    { 
      setr[(*psizer)++] = set2[i];
    }
  }
  setr = realloc( setr, *psizer*sizeof(setr[0]));
  return setr;
}


C++ с другой стороны, с мощью своей стандартной библиотеки позволяет вам совершенно другой подход
#include <iostream>
#include <set>
using namespace std;

int main()
{
  set<int> set1{3, 5, 6,-1, 42, 28};
  set<int> set2{100, 5, -23, 42,18};

  set<int> setr{set1};
  setr.insert( set2.begin(), set2.end() );
  for (auto x : setr)
    cout << x << " ";
  cout << endl;
}