char ** argv 또는 char * argv []를 사용해야합니까?


125

나는 단지 C를 배우고 있으며 주요 방법으로 사용해야하는 것이 무엇인지 궁금합니다. 차이점이 있습니까? 어느 것이 더 흔합니까?


2
나는 'char ** argv'를 선호하므로 더 자주 볼 수 있지만 둘 다 정확하며 'char * argv []'로 작성 되었기 때문에 선언을 변경하지 않습니다.
Jonathan Leffler

배열 대 포인터의 더 깊은 문제가 잘 이해되기 때문에 +1입니다.
RBerteig

2
정말 좋은 질문입니다. 감사합니다.
Frank V

5
comp.lang.c FAQ 의 섹션 6을 읽으십시오 . C 배열과 내가 본 포인터 사이의 관계에 대한 가장 좋은 설명입니다. 두 관련 사항 : 1. char **argv정확히 동일합니다 char *argv[]매개 변수 선언으로 (그리고 유일한 매개 변수 선언과 같은). 2. 배열은 포인터가 아닙니다.
Keith Thompson

답변:


160

C를 배우는 동안 일반적인 것 대신 배열과 포인터 의 차이점 을 먼저 이해하는 것이 좋습니다 .

매개 변수 및 배열 영역에는 몇 가지 혼란스러운 규칙이 있으므로 계속 진행해야합니다. 먼저 매개 변수 목록에서 선언 한 내용은 특별하게 취급됩니다. C에서 함수 매개 변수로 이해가되지 않는 상황이 있습니다.

  • 매개 변수로서의 기능
  • 매개 변수로서의 배열

매개 변수로서의 배열

두 번째는 즉시 명확하지 않을 수 있습니다. 그러나 배열 차원의 크기가 C의 유형의 일부라고 생각할 때 명확합니다 (차원 크기가 주어지지 않은 배열은 불완전한 유형을 가짐). 따라서 값으로 배열을 가져 오는 함수 (복사본을받는 함수)를 만들면 한 가지 크기로만 수행 할 수 있습니다! 또한 배열이 커질 수 있으며 C는 가능한 한 빨리 노력합니다.

C에서는 이러한 이유로 배열 값 이 존재하지 않습니다. 배열의 값을 얻으려면 대신 배열의 첫 번째 요소에 대한 포인터입니다. 그리고 여기에 실제로 해결책이 있습니다. C 컴파일러는 유효하지 않은 배열 매개 변수를 그리는 대신 각 매개 변수의 유형을 포인터로 변환 합니다. 이것을 기억하십시오, 그것은 매우 중요합니다. 매개 변수는 배열이 아니라 대신 해당 요소 유형에 대한 포인터입니다.

이제 배열을 전달하려고하면 대신 전달되는 것은 배열의 첫 번째 요소에 대한 포인터입니다.

소풍 : 매개 변수로 기능

완성을 위해, 이것이 문제를 더 잘 이해하는 데 도움이 될 것이라고 생각하기 때문에 매개 변수로 함수를 사용하려고 할 때 업무 상태가 무엇인지 살펴 보겠습니다. 실제로, 먼저 이해가되지 않습니다. 매개 변수는 어떻게 함수가 될 수 있습니까? 물론, 우리는 그 장소에서 변수를 원합니다! 따라서 컴파일러가 발생할 때 수행하는 작업은 다시 함수를 함수 포인터변환 하는 것 입니다. 함수를 전달하려고하면 해당 함수에 대한 포인터가 대신 전달됩니다. 따라서 다음은 동일합니다 (배열 예제와 유사).

void f(void g(void));
void f(void (*g)(void));

괄호 *g가 필요합니다. 그렇지 않으면 반환하는 함수 void*에 대한 포인터 대신 반환하는 함수를 지정합니다 void.

배열로 돌아 가기

이제 처음에는 배열에 불완전한 유형이있을 수 있다고 말했습니다. 아직 크기를 지정하지 않으면 발생합니다. 우리는 이미 배열 매개 변수가 존재하지 않지만 대신 배열 매개 변수가 포인터라는 것을 알았으므로 배열의 크기는 중요하지 않습니다. 즉, 컴파일러는 다음을 모두 번역하며 모두 동일합니다.

int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);

물론 크기를 넣을 수있는 것은 이치에 맞지 않으며 그냥 버려집니다. 이런 이유로 C99는 그 숫자에 새로운 의미를 부여했으며 대괄호 사이에 다른 것들이 나타날 수 있습니다.

// says: argv is a non-null pointer pointing to at least 5 char*'s
// allows CPU to pre-load some memory. 
int main(int c, char *argv[static 5]);

// says: argv is a constant pointer pointing to a char*
int main(int c, char *argv[const]);

// says the same as the previous one
int main(int c, char ** const argv);

마지막 두 줄은 함수 내에서 "argv"를 변경할 수 없다고 말합니다. const 포인터가되었습니다. 그래도 C99 기능을 지원하는 C 컴파일러는 거의 없습니다. 그러나 이러한 기능을 통해 "배열"이 실제로는 아니라는 것을 알 수 있습니다. 포인터입니다.

경고의 말

위에서 말한 것은 함수 의 매개 변수 로 배열을 얻은 경우에만 해당됩니다 . 로컬 배열로 작업하는 경우 배열은 포인터가 아닙니다. 윌 동작 값 읽을 때 등의 이전 포인터 배열로 변환한다 설명하기 때문에, 포인터로. 그러나 포인터와 혼동해서는 안됩니다.

대표적인 예는 다음과 같습니다.

char c[10]; 
char **c = &c; // does not work.

typedef char array[10];
array *pc = &c; // *does* work.

// same without typedef. Parens needed, because [...] has 
// higher precedence than '*'. Analogous to the function example above.
char (*array)[10] = &c;

2
이것이 존재
하는지

12

어느 쪽이든 사용할 수 있습니다. 그것들은 완전히 같습니다. litb 의 의견과 답변을 참조하십시오 .

실제로 사용 방법에 달려 있습니다 (어쨌든 어느 쪽이든 사용할 수 있습니다).

// echo-with-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char **argv)
{
  while (--argc > 0)
  {
    printf("%s ", *++argv);
  }
  printf("\n");
  return 0;
}

// echo-without-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char *argv[])
{
  int i;
  for (i=1; i<argc; i++)
  {
    printf("%s ", argv[i]);
  }
  printf("\n");
  return 0;
}

어느 것이 더 일반적인지는 중요하지 않습니다. 코드를 읽는 숙련 된 C 프로그래머는 둘 다 호환 가능한 것으로 간주합니다 (올바른 조건에서). 숙련 된 영어 사용자가 "그들"과 "그들"을 똑같이 쉽게 읽는 것처럼.

더 중요한 것은 당신이 그것들을 읽고 그것들이 얼마나 비슷한지를 배우는 것입니다. 작성하는 것보다 더 많은 코드를 읽을 수 있으며 두 가지 모두에 대해 똑같이 편안해야합니다.


7
char * argv []는 함수의 매개 변수 유형으로 사용될 때 char ** argv와 100 % 동일합니다. 암묵적으로 "const"도 포함되지 않습니다. 둘 다 문자를 가리키는 포인터입니다. 선언 한 내용과 다릅니다. 그러나 컴파일러는 배열이라고 말했지만 매개 변수 유형을 포인터에 대한 포인터로 조정합니다. 따라서 다음은 모두 동일합니다. void f (char * p [100]); 무효 f (char * p []); 무효 f (char ** p);
Johannes Schaub-litb

4
C89 (대부분의 사람들이 사용하는)에는 배열로 선언 했다는 사실을 활용할 수있는 방법 이 없습니다. 따라서 의미 적으로 포인터 또는 배열을 선언했는지 여부는 중요하지 않습니다. 바늘). C99부터는 배열로 선언하면 도움이됩니다. "p는 항상 널이 아니며 최소 100 바이트가있는 영역을 가리 킵니다": void f (char p [static 100]); 그러나 유형별 p는 여전히 포인터입니다.
요하네스 샤 우브-litb

5
(특히 & p는 char **를 주지만 p *가 배열 이면 char ( ) [100] 은 제공하지 않습니다 ). 아무도 대답에 아무도 언급하지 않은 것에 놀랐습니다. 이해하는 것이 매우 중요하다고 생각합니다.
Johannes Schaub-litb

개인적으로 나는 그것을하는 char**것처럼 실제 배열로 취급해서는 안된다는 것을 상기시키기 때문에 선호합니다 sizeof[arr] / sizeof[*arr].
raymai97

9

차이는 없지만 char *argv[]가변 길이 문자열 (보통 char *) 의 고정 크기 배열임을 보여주기 때문에 사용 합니다 .



4

실제로 차이를 만들지는 않지만 후자는 더 읽기 쉽습니다. 두 번째 버전과 같이 char 포인터 배열이 제공됩니다. 그러나 첫 번째 버전에서와 같이 암시 적으로 이중 문자 포인터로 변환 될 수 있습니다.


2

그것을 선언 char *argv[]하는 많은 동등한 방법으로 인해 직관적 인 의미에 가장 가까운 문자열 배열로 선언해야합니다.


1

char ** → 문자 포인터에 대한 포인터 및 char * argv []는 문자 포인터의 배열을 의미합니다. 배열 대신 포인터를 사용할 수 있으므로 둘 다 사용할 수 있습니다.


0

다른 방법 대신 두 가지 방법 중 하나를 사용하는 특별한 장점이 없습니다. 다른 코드와 가장 일치하는 규칙을 사용하십시오.


-2

다양하거나 동적 인 문자열 수가 필요한 경우 char **를 사용하는 것이 더 쉬울 수 있습니다. 문자열 수가 고정되어 있으면 char * var []가 선호됩니다.


-2

나는 이것이 구식이라는 것을 알고 있지만 C 프로그래밍 언어를 배우고 주요 기능을 수행하지 않는다면 명령 줄 옵션을 사용하지 마십시오.

명령 행 인수를 사용하지 않는 경우 둘 중 하나를 사용하지 마십시오. 그냥 메인 함수를 선언 같은 int main() 경우

  • 프로그램 사용자가 파일을 프로그램으로 끌어서 프로그램의 결과를 변경할 수 있도록하려면
  • 명령 행 옵션 ( -help, /?또는 program name터미널 또는 명령 프롬프트에서 뒤 따르는 기타 항목) 을 처리하려고 합니다.

당신에게 더 의미있는 것을 사용하십시오. 그렇지 않으면 int main() 결국 사용 하십시오. 명령 행 옵션을 추가하려는 경우 나중에 쉽게 편집 할 수 있습니다.


이것은 질문에 대답하지 않습니다.
룬딘
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.