C의 함수에 인수로 배열 전달
배열이 들어 있는 함수를 인수로 썼고, 배열이란 값을 다음과 같이 전달하여 부른다.
void arraytest(int a[])
{
// changed the array a
a[0] = a[0] + a[1];
a[1] = a[0] - a[1];
a[0] = a[0] - a[1];
}
void main()
{
int arr[] = {1, 2};
printf("%d \t %d", arr[0], arr[1]);
arraytest(arr);
printf("\n After calling fun arr contains: %d\t %d", arr[0], arr[1]);
}
내가 찾은 건 내가 전화했음에도 불구하고arraytest()
의 원본 복사본인 값을 전달함으로써 기능한다.int arr[]
바뀌었어.
이유를 설명해 주시겠습니까?
배열을 매개 변수로 전달할 때
void arraytest(int a[])
와 정확히 같은 뜻을 가지고 있다.
void arraytest(int *a)
그래서 당신은 주 단위로 값을 수정하는 것이다.
역사적 이유로 배열은 일등 시민이 아니며 가치로 전달될 수 없다.
대신 2D(또는 다차원 이상) 어레이를 전달하려면 여기에서 다른 답변을 참조하십시오.다차원 배열을 C 및 C++의 함수에 전달하는 방법
C(및 C++)에서 기능 매개 변수로 1D 어레이 전달
1.배열에서 ptr까지 자연형 부패(조정)가 있는 C의 표준배열 사용법
@Bo Persson은 여기서 그의 위대한 대답에서 다음과 같이 정확하게 말한다.
배열을 매개 변수로 전달할 때
void arraytest(int a[])
와 정확히 같은 뜻을 가지고 있다.
void arraytest(int *a)
다음 두 가지 코드 스니펫에 명확성을 추가하기 위해 몇 가지 의견을 추가하겠다.
// param is array of ints; the arg passed automatically "adjusts" (frequently said
// informally as "decays") from `int []` (array of ints) to `int *`
// (ptr to int)
void arraytest(int a[])
// ptr to int
void arraytest(int *a)
그러나 위의 두 가지 형태도 또한 다음과 같이 덧붙이자면:
와 정확히 같은 뜻이다
// array of 0 ints; automatically adjusts (decays) from `int [0]` // (array of zero ints) to `int *` (ptr to int) void arraytest(int a[0])
그 말은 정확히 같은 뜻이야
// array of 1 int; automatically adjusts (decays) from `int [1]` // (array of 1 int) to `int *` (ptr to int) void arraytest(int a[1])
그 말은 정확히 같은 뜻이야
// array of 2 ints; automatically adjusts (decays) from `int [2]` // (array of 2 ints) to `int *` (ptr to int) void arraytest(int a[2])
그 말은 정확히 같은 뜻이야
// array of 1000 ints; automatically adjusts (decays) from `int [1000]` // (array of 1000 ints) to `int *` (ptr to int) void arraytest(int a[1000])
등
위의 모든 배열 예에서, 그리고 바로 아래의 코드에 있는 호출 예에서와 같이, 입력 매개변수 유형은 로 조정(결정)되며, 빌드 옵션에서도 경고와 오류 없이 호출될 수 있다.-Wall -Wextra -Werror
다음과 같이 설정됨(이 3가지 빌드 옵션에 대한 자세한 내용은 여기에서 my repo 참조):
int array1[2];
int * array2 = array1;
// works fine because `array1` automatically decays from an array type
// to a pointer type: `int *`
arraytest(array1);
// works fine because `array2` is already an `int *`
arraytest(array2);
"의 가치사, "기" 값 ("기" 값)[0]
[1]
[2]
[1000]
, 등) 여기서 배열 매개변수 내부에는 분명히 심미적/자기 만족을 위한 것이며, 어떤 양의 정수일 수 있다.size_t
(타입) 원하시는 거 아니에요!
그러나 실제로는 함수가 수신할 것으로 예상되는 배열의 최소 크기를 지정하기 위해 코드를 작성할 때 쉽게 추적하고 확인할 수 있도록 이 값을 사용해야 한다.MISRA-C-2012 표준(여기서 £15.00에 대한 표준의 236-pg 2012 버전 PDF를 구입/다운로드)은 다음과 같이까지 언급된다(강조 추가).
규칙 17.5배열 유형을 갖는 것으로 선언된 매개변수에 해당하는 함수 인수는 적절한 수의 요소를 가져야 한다.
...
매개변수가 지정된 크기를 가진 배열로 선언된 경우, 각 함수 호출의 해당 인수는 적어도 배열과 같은 수의 요소를 가진 객체를 가리켜야 한다.
...
함수 매개변수에 배열 선언기를 사용하는 것은 포인터를 사용하는 것보다 함수 인터페이스를 더 명확하게 지정한다.기능에 의해 예상되는 최소 원소 수가 명시되어 있는 반면, 포인터로는 이것이 가능하지 않다.
즉, 기술적으로 C 표준이 이를 강제하지는 않지만 명시적 크기 형식을 사용할 것을 권고한다. 최소한 개발자로서 귀하에게 도움이 되고, 코드를 사용하는 다른 사람들에게, 해당 함수가 전달할 것으로 예상되는 크기 배열을 명확히 하는 데 도움이 된다.
2. C의 배열에 형식 안전 강제
(권장되지 않음(수정: 때로는 권장됨, 특히 고정 크기 다차원 배열의 경우 권장됨) 그러나 가능하다.마지막에 이것을 하는 것에 반대하는 나의 짧은 주장을 보라.또한, 나의 다차원 어레이 [ex: 2D 어레이] 버전에 대해서는, 여기서 내 대답을 참조하십시오.)
@Winger Sendon이 내 대답 아래의 코멘트에서 지적했듯이, 우리는 C가 배열 크기에 따라 배열 유형을 다르게 취급하도록 강제할 수 있다!
첫째, 바로 위의 제 예에서, 당신은 그것을 인식해야 한다.int array1[2];
다음과 같은 경우:arraytest(array1);
원인들array1
자동으로 a로 부패하다int *
하지만, 만약 당신이 대신 주소를 가지고 전화를 한다면, 당신은 완전히 다른 행동을 하게 될 것이다!이제, 그것은 썩지 않는다.int *
! 배열의 주소를 가져갈 경우 이미 포인터 유형이 있고 포인터 유형이 다른 포인터 유형에 조정되지 않기 때문이다.배열 유형만 포인터 유형에 맞게 조정하십시오.그래서 그 대신 그 종류는&array1
는 "int의 크기 2 배열로" 또는 "int 유형의 크기 2 배열로"를 의미하거나 "2 int의 배열로"를 의미하기도 한다.따라서 다음과 같이 어레이에 명시적 포인터를 전달하여 어레이의 유형 안전을 강제로 확인할 수 있다.
// `a` is of type `int (*)[2]`, which means "pointer to array of 2 ints";
// since it is already a ptr, it can NOT automatically decay further
// to any other type of ptr
void arraytest(int (*a)[2])
{
// my function here
}
이 구문은 읽기 어렵지만 함수 포인터와 유사하다.온라인 도구 cdel은 우리에게int (*a)[2]
평균: "int의 배열 2에 대한 포인터로 a 설정"(2의 배열)int
s). 이 버전을 와의 버전과 혼동하지 마십시오.OUT 괄호:int * a[2]
, 즉: "int에 대한 포인터 배열 2로 선언"(AKA: 다음에 대한 포인터 2개 배열)int
, AKA: 배열 2int*
s).
이제, 이 함수는 주소 운영자와 통화할 것을 요구한다.&
) 이렇게 입력 매개 변수로 올바른 크기의 배열에 대한 포인터를 사용하십시오!:
int array1[2];
// ok, since the type of `array1` is `int (*)[2]` (ptr to array of
// 2 ints)
arraytest(&array1); // you must use the & operator here to prevent
// `array1` from otherwise automatically decaying
// into `int *`, which is the WRONG input type here!
그러나 이는 다음과 같은 경고를 발생시킬 것이다.
int array1[2];
// WARNING! Wrong type since the type of `array1` decays to `int *`:
// main.c:32:15: warning: passing argument 1 of ‘arraytest’ from
// incompatible pointer type [-Wincompatible-pointer-types]
// main.c:22:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
arraytest(array1); // (missing & operator)
C 컴파일러가 이 경고를 오류로 전환하도록 강제하여 항상 전화를 걸어야 함arraytest(&array1);
올바른 크기 및 유형의 입력 배열만 사용(int array1[2];
이 경우), 추가-Werror
원하는 빌드 옵션을 선택하십시오.onlinegdb.com에서 위의 테스트 코드를 실행하는 경우 오른쪽 상단에 있는 기어 아이콘을 클릭하고 "추가 컴파일러 플래그"를 클릭하여 이 옵션을 입력하십시오. 이 자, 이려고:
main.c:34:15: warning: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Wincompatible-pointer-types] main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
이 빌드 오류로 전환됨:
main.c: In function ‘main’: main.c:34:15: error: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Werror=incompatible-pointer-types] arraytest(array1); // warning! ^~~~~~ main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’ void arraytest(int (*a)[2]) ^~~~~~~~~ cc1: all warnings being treated as errors
다음과 같이 지정된 크기의 배열로 "유형 안전" 포인터를 만들 수도 있다는 점에 유의하십시오.
int array[2]; // variable `array` is of type `int [2]`, or "array of 2 ints"
// `array_p` is a "type safe" ptr to array of size 2 of int; ie: its type
// is `int (*)[2]`, which can also be stated: "ptr to array of 2 ints"
int (*array_p)[2] = &array;
...하지만 반드시 이것을 권장하지는 않는다(C의 이러한 "유형 안전" 배열 사용), 언어 구문 복잡성, 장황함, 그리고 난이도의 예외적으로 높은 비용으로 어디에서나 형식 안전을 강제할 때 사용되었던 많은 C++ 익살스러움을 상기시켜 주고, 내가 이전에 여러 번 혐오하고 원했던 것(예: "내 생각" 참조)여기 C++"에 표시하십시오.
추가 테스트 및 실험은 아래 링크를 참조하십시오.
참조
위의 링크를 참조하십시오.또한:
- 내 코드 온라인 실험: https://onlinegdb.com/B1RsrBDFD
참고 항목:
- 위에 설명된 다차원 배열(예: 2D 배열)에 대한 나의 답변은 다음과 같은 의미가 있는 다차원 배열에서 "유형 안전" 접근방식을 사용한다.다차원 배열을 C 및 C++의 함수에 전달하는 방법
함수의 인수로 단일차원 배열을 통과시키려면 다음 세 가지 방법 중 하나로 공식 매개변수를 선언해야 하며, 각 방법이 컴파일러에게 정수 포인터를 수신할 것임을 알려주기 때문에 세 가지 선언 방법 모두 유사한 결과를 도출한다.
int func(int arr[], ...){
.
.
.
}
int func(int arr[SIZE], ...){
.
.
.
}
int func(int* arr, ...){
.
.
.
}
따라서 원래 값을 수정하는 것이다.
고마워 !!!
함수에 인수로 다차원 배열 전달.하나의 모호한 배열을 인수로 전달하는 것은 다소 사소한 일이다.2개의 희미한 배열을 통과하는 더 흥미로운 사례에 대해 살펴봅시다.C에서 포인터를 사용하여 포인터 구문을 만들 수 없음(int **
2개의 딤 배열 대신 )예를 들어보자:
void assignZeros(int(*arr)[5], const int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 5; j++) {
*(*(arr + i) + j) = 0;
// or equivalent assignment
arr[i][j] = 0;
}
}
여기서 나는 첫 번째 인수로 5개의 정수의 배열에 대한 포인터를 취하는 함수를 지정했다.다음과 같은 5개의 열이 있는 2개의 딤 어레이를 인수로 전달할 수 있다.
int arr1[1][5]
int arr1[2][5]
...
int arr1[20][5]
...
2개의 딤 어레이를 수용하고 다음과 같이 함수 서명을 변경할 수 있는 보다 일반적인 함수를 정의하기 위한 아이디어를 얻을 수 있다.
void assignZeros(int ** arr, const int rows, const int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
*(*(arr + i) + j) = 0;
}
}
}
이 코드는 컴파일되지만 첫 번째 함수에서와 같은 방법으로 값을 할당하려고 할 때 런타임 오류가 발생한다.따라서 C에서 다차원 배열은 포인터의 포인터와 같지 않다... 포인터의 포인터...안int(*arr)[5]
5개의 원소 배열에 대한 포인터,int(*arr)[6]
이다!6개의 원소 배열에 대한 포인터고, 그것들은 다른 종류의 포인터야!
음, 어떻게 더 높은 차원에 대한 함수 인수를 정의할 수 있을까?간단해, 그냥 패턴을 따르는 거야!다음은 3차원의 배열을 취하도록 조정된 것과 동일한 기능이다.
void assignZeros2(int(*arr)[4][5], const int dim1, const int dim2, const int dim3) {
for (int i = 0; i < dim1; i++) {
for (int j = 0; j < dim2; j++) {
for (int k = 0; k < dim3; k++) {
*(*(*(arr + i) + j) + k) = 0;
// or equivalent assignment
arr[i][j][k] = 0;
}
}
}
}
예상한 대로, 2차원의 4차원과 3차원의 5차원의 3개 조광 배열을 인수로 사용할 수 있다.이런 거라면 아무거나 괜찮아.
arr[1][4][5]
arr[2][4][5]
...
arr[10][4][5]
...
하지만 첫 번째 치수까지 모든 치수를 지정해야 해.
어레이의 첫 번째 멤버의 메모리 위치 값을 전달하고 있는 경우.
따라서 함수 내부의 배열을 수정하기 시작하면 원래 배열을 수정하는 것이다.
그 것을 기억하라.a[1]
이다*(a+1)
.
C의 배열은 대부분의 경우 배열 자체의 첫 번째 요소에 대한 포인터로 변환된다.그리고 보다 세부적으로 함수로 전달되는 배열은 항상 포인터로 전환된다.
K&R2nd의 인용문:
배열 이름이 함수에 전달될 때 전달되는 것은 초기 요소의 위치다.호출된 함수 내에서 이 인수는 로컬 변수이므로 배열 이름 매개 변수는 포인터, 즉 주소를 포함하는 변수다.
쓰기:
void arraytest(int a[])
다음과 같은 의미를 갖는다.
void arraytest(int *a)
그래서 당신이 그것을 명시적으로 쓰지 않아도 그것은 당신이 포인터를 통과하고 있기 때문에 당신은 메인에서 값을 수정하고 있다.
더 많은 것을 위해 나는 정말로 이것을 읽는 것을 추천한다.
또한 SO에서 다른 해답을 찾을 수 있다.
배열을 사본으로 전달하지 마십시오.이는 배열의 첫 번째 요소가 메모리에 있는 주소를 가리키는 포인터일 뿐이다.
배열의 첫 번째 요소의 주소를 전달하는 경우
사용할 경우 배열이 항상 참조로 전달됨a[]
또는*a
:
int* printSquares(int a[], int size, int e[]) {
for(int i = 0; i < size; i++) {
e[i] = i * i;
}
return e;
}
int* printSquares(int *a, int size, int e[]) {
for(int i = 0; i < size; i++) {
e[i] = i * i;
}
return e;
}
C에서 몇 가지 특별한 경우를 제외하고 배열 참조는 항상 배열의 첫 번째 요소에 대한 포인터를 "결정"한다.따라서 "값별" 배열을 전달할 수 없다.함수 호출의 배열이 포인터로서 함수에 전달되며, 이는 배열을 참조로 전달하는 것과 유사하다.
편집: 어레이가 첫 번째 요소에 대한 포인터까지 손상되지 않는 특별한 경우:
sizeof a
와 같지 않다sizeof (&a[0])
.&a
와 같지 않다&(&a[0])
(그리고 와는 전혀 같지 않다.&a[0]
).char b[] = "foo"
와 같지 않다char b[] = &("foo")
.
배열은 붕괴 포인터라고도 할 수 있다.
일반적으로 출력 f 문장에 변수 이름을 입력하면 배열의 경우 값이 인쇄되어 첫 번째 원소의 주소로 디코딩되므로 이를 붕괴 포인터라고 부른다.
그리고 우리는 기능에만 붕괴 포인터를 전달할 수 있다.
Mr.Bo가 말한 바와 같이 형식적인 매개변수로서의 배열은 int ar[] 또는 int ar[10]는 int *arr;
그들은 4바이트의 메모리 공간을 가지고 있고 수신된 붕괴 포인터를 저장할 것이다.포인터로 산수를 하는 거야
참조URL: https://stackoverflow.com/questions/6567742/passing-an-array-as-an-argument-to-a-function-in-c
'Programing' 카테고리의 다른 글
java : float를 String으로, String을 Float로 변환 (0) | 2022.05.14 |
---|---|
Vue.js - Vuex 모듈에서 현재 경로 가져오기 (0) | 2022.05.14 |
시작 시 NUXTJS Store 상태 콘텐츠를 채우시겠습니까? (0) | 2022.05.14 |
C는 "예측" 루프 구조를 가지고 있는가? (0) | 2022.05.14 |
vm 사용.여러 번 콜백을 처리하는 데 한 번보다 여러 번 더 많은 비용을 지출하시겠습니까? (0) | 2022.05.14 |