문제

다음 코드를 컴파일 할 때 :

void DoSomething(int Numbers[])
{
    int SomeArray[] = Numbers;
}

vs2005 컴파일러는 오류 C2440에 불만을 제기합니다. '초기화': 'int []'에서 'int []로'int [] '에서 변환 할 수 없습니다.

나는 그것이 작동하지 않을 배열에 대한 포인터를 시전하려고한다는 것을 이해합니다. 그러나 C ++를 배우는 사람에게 오류를 어떻게 설명합니까?

도움이 되었습니까?

해결책

당신이 돕고 자하는 사람에게 설명해야 할 세 가지가 있습니다.

  1. 배열은 C ++의 함수로 값으로 전달할 수 없습니다. 당신이하려는 일을하려면 배열 시작 주소를 전달해야합니다. DoSomething(), 분리 된 배열의 크기뿐만 아니라 int (잘, size_t, 그러나 나는 그렇게 말하는 것을 귀찮게하지 않을 것입니다) 논쟁. 일부 배열 시작 주소를 얻을 수 있습니다. myArray 표현과 함께 &(myArray[0]). 이것은 원하는 일반적인 일이므로 C ++는 배열의 이름 만 사용할 수 있습니다. myArray - 첫 번째 요소의 주소를 얻습니다. C ++는 배열 유형을 지정할 수 있습니다 (예 : int Numbers[]) 함수에 대한 매개 변수로서, 그러나 비밀리에 매개 변수는 마치 포인터로 선언 된 것처럼 취급합니다 (int *Numbers 이 경우) - 할 수도 있습니다 Numbers += 5 내부에 DoSomething() 여섯 번째 위치에서 시작하는 배열을 가리 킵니다!

  2. 다음과 같은 배열 변수를 선언 할 때 SomeArray C ++에서는 명시 적 크기 또는 "이니셜리스트 목록"을 제공해야합니다., 이것은 쉼표로 구분 된 값의 값 목록입니다. 컴파일러가 초기화하려는 다른 배열을 기반으로 배열의 크기를 추론 할 수 없습니다.

  3. 한 배열을 다른 배열로 복사하거나 C ++의 다른 배열에서 하나의 배열을 초기화 할 수 없습니다. 따라서 매개 변수라도 Numbers 실제로 배열 (크기 1000)이었고 포인터가 아니 었으며 크기를 지정했습니다. SomeArray (다시 1000으로) 라인 int SomeArray[1000] = Numbers; 불법입니다.


당신이하고 싶은 일을하기 위해 DoSomething(), 먼저 스스로에게 물어보세요 :

  1. 값을 변경해야합니까? Numbers?
  2. 그렇다면 발신자가 이러한 변경 사항을 보지 못하게하고 싶습니까?

두 질문에 대한 답이 "아니오"라면 실제로 사본을 만들 필요는 없습니다. Numbers 우선 - 그냥 그대로 사용하고 별도의 것을 잊어 버리십시오. SomeArray 정렬.

두 질문 모두에 대한 답이 "예"인 경우 사본을 만들어야합니다. Numbers 안에 SomeArray 대신 작업하십시오. 이 경우 실제로 만들어야합니다 SomeArray C ++ vector<int> 이것은 다른 배열 대신 실제로 물건을 단순화합니다. (수동 동적 메모리 할당에 대한 벡터의 이점을 설명합니다. ~할 수 있다 다른 배열 또는 벡터에서 초기화되면 C 스타일과 달리 필요한 경우 요소 생성자를 호출합니다. memcpy().)

다른 팁

유형과 불완전한 유형이 있다고 가정하십시오.

struct A;

A라는 구조물의 불완전한 유형입니다.

struct A { };

A라는 구조물의 완전한 유형입니다. 첫 번째 크기는 아직 알려지지 않았으며 두 번째 크기는 알려져 있습니다.

위 구조물과 같은 불완전한 클래스 유형이 있습니다. 그러나 불완전한 배열 유형도 있습니다.

typedef int A[];

그것은 A라는 불완전한 배열 유형입니다. 크기는 아직 알려져 있지 않습니다. 컴파일러가 배열이 얼마나 큰지 알지 못하기 때문에 배열을 만들 수 없습니다. 하지만 당신은 할 수 있습니다 사용 배열을 만들기 위해 바로 초기화하면 :

A SomeArray = { 1, 2, 3 };

이제 컴파일러는 배열이 3 개의 요소가있는 int 배열임을 알고 있습니다. 포인터로 배열을 초기화하려고하면 컴파일러가 이전보다 더 영리하지 않으며 거부 할 배열의 크기를 제공하지 않기 때문에 거부합니다.

오류 메시지를보다 도움이 되려고 노력할 때 컴파일러는 실제로 혼란 스럽습니다. 비록 Numbers 매개 변수는 배열로 선언되며 C/C ++는 실제로 배열을 전달할 수 없습니다 - Numbers 매개 변수는 실제로 포인터입니다.

따라서 오류는 실제로 말해야합니다 "cannot convert from 'int *' to 'int []'"

하지만 혼란이있을 것입니다 - "이봐, int* 표현에 관여한다 ", 누군가는 말할 수있다.

이러한 이유로 배열 매개 변수를 피하는 것이 실제로 좋습니다. 그리고 C/C ++를 배우는 사람에 대한 설명은 배열 매개 변수가 허구라는 사실에 대해 교육해야합니다. 그들은 실제로 포인터입니다.

내가 무언가를 설명하려고 할 때, 나는 항상 가장 낮은 수준으로 내려 가서 거기에서 쌓이려 고 노력합니다. 그것이 내가 배우고 싶어하는 방식이며, 그들이 알고있는 기본 사항을 시작하고 거기에서 쌓이면 사람들이 더 편한다는 것을 알게됩니다.

이 경우 아마도 다음과 같은 것으로 시작합니다.

할당 작업을 작성했기 때문에 컴파일러가 과제를 수행하려고합니다. C ++에서는 배열에 직접 할당 할 수 없습니다 (모든 종류의 할당 연산자가 없기 때문에) (모든 종류의 이니셜 라이저 및 인덱싱 만 배열에 대한 지원). C ++는 유형에 대해 과부하 된 연산자를 지원하기 때문에 컴파일러는 "할당 된"유형을 인수로 가져 오는 "할당 된"유형의 과부하 할당 연산자를 찾습니다. int []를 인수로 가져 오는 int []에 대한 오버로드 된 연산자도 없기 때문에 라인의 컴파일러 오류가 발생하며 오류가 컴파일러가 라인을 처리 할 수없는 이유를 알려줍니다.

그렇습니다. 아마도 크기, 불완전한 유형 등에 대한 지식에 대해 말하는 것보다 과도한 일일 것입니다. 나는 그것이 완전하지 않다는 것을 알고 있습니다 (예 : 초기 할인 할당 대 일반 할당 등에 대한 논의 없음). 그러나 저의 목표는 일반적으로 사람들이 다음 답변을 파악할 수있는 곳으로 데려가는 것입니다.이 때문에 대개 답변에 도달하기위한 사고 과정을 제시하고자합니다.

아마도 당신의 대답은 "컴파일러가 배열이 얼마나 큰지 모르기 때문에"일 수 있습니다.

명백한 배열 크기 (명확성을위한 typedef)가있는 경우 예제가 작동 할 수 있으며 가변 크기 할당을 도입하면서 포인터를 설명 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top