2009-05-08 5 views
5

켜기 K & R 109, 우리는 다음을 참조하십시오K & R : 문자 포인터 배열

void writelines(char *lineptr[], int nlines) 
{ 
    while (nlines -- > 0) printf("%s\n", *lineptr++); 
} 

내가 * lineptr는 ++ 정확히 무엇을하는지에 대한 혼란 스러워요. 내 이해에서, printf는 char 포인터를 필요로하므로 * lineptr을 제공한다. 그런 다음 배열의 다음 char 포인터까지 lineptr을 증가시킵니다. 이건 불법이 아닌가?

페이지에서 K & R은 "배열 이름은 변수가 아니며 a = pa [여기서 a는 배열이고 pa는 배열에 대한 포인터입니다] 및 ++는 불법입니다"라고 씁니다.

답변

4

아담 로젠 필드의 대답이 잘못되었습니다. coobird의 대답도. 그 이유로 나는 두 답을 모두 썼다.

*lineptr++의 Adam Markowitz 해석은 맞지만이 것이 합법적 인 C99 코드인지 여부에 대한 주요 질문에는 답하지 않습니다. 오직 Tom Future만이; 불행히도 그는 설명하지 않는다 *lineptr++. 나는 그들에게 각각 한 점을 부여했다.

간단히 말해서 lineptr은 변수이며 포인터로 조작 할 수 있습니다. 따라서 포인터를 증가시키는 것이 타당합니다.

은 char 시퀀스에 대한 포인터 시퀀스에 대한 포인터입니다. 즉, 문자열 배열의 첫 번째 문자열에 대한 포인터입니다. 코드에 따르면 문자열이 null ('\ 0') 종료 문자 시퀀스라고 가정 할 수 있습니다. nlines은 배열의 문자열 수입니다.

while 테스트 식은 ​​nlines-- > 0입니다. nlines--은 (변수의 오른쪽에 --이 있기 때문에) 후행 감소입니다. 따라서 후에 테스트가 수행되었고 테스트 결과에 관계없이 어떠한 경우에도 이 실행됩니다.

따라서 인수로 주어진 nlines 값이 0 인 경우 테스트가 먼저 수행되고 false을 반환합니다. 루프의 명령은 실행되지 않습니다. 어쨌든 nlines이 감소하므로 while 루프 다음에 nlines 값은 -1이됩니다.

nlines == 1 인 경우 테스트는 true이고, nlines은 감소합니다. 루프의 명령은 한 번 실행됩니다. 이 명령어가 실행되는 동안 nlines의 값은 0입니다. 테스트가 다시 수행되면 nlines == 0으로 돌아갑니다.

printf 명령어는 *lineptr++ 표현식을 사용합니다. 포인터의 후행 증가 (++은 변수의 오른쪽에 있음)입니다. 이것은 표현식이 먼저 평가되고 증가가 후에 사용 된 을 의미합니다. 따라서 첫 번째 실행시 printf은 문자열 배열의 첫 번째 요소 사본을받습니다.이 배열은 문자열의 첫 번째 문자에 대한 포인터입니다. lineptr은 그 이후에만 증가됩니다. 다음에 printf이 실행될 때 lineptr은 두 번째 요소를 가리키고 두 번째 문자열이 인쇄되면 세 번째 요소로 이동합니다. 우리가 분명히 첫 번째 문자열을 인쇄하기 때문에 이것은 의미가 있습니다. Adam Rosenfield가 맞다면 첫 번째 문자열은 건너 뛰게 될 것이고 마지막에는 분명히 나쁜 것 인 마지막 문자열을 넘어서 문자열을 인쇄하려고합니다.

그래서, printf 명령은 다음과 같은 두 가지 지침

printf("%s\n", *lineptr); 
++lineptr; // or lineptr++, which is equivalent but not as good. lineptr += 1; is ok too. 

주 간결한 형태는 엄지 손가락의 규칙으로,입니다 사전 및 사후 증가가 자신의 행동 동일, 사전 증가는 성능상의 이유로 바람직합니다. 컴파일러는 당신을 위해 그것을 돌보아 줄 것입니다. 글쎄, 대부분의 시간. 가능한 한 항상 사전 운영자에게 더 낫기 때문에 항상 사용됩니다. 그 이유는 C + +에서 포스트 및 사전 증가를 구현하면 더욱 명백해진다.

+0

명확히 해 주셔서 고마워요 ... 내가 미쳐 가는지 아닌지 궁금 해서요 :) –

6

lineptr은 실제로 배열이 아닙니다. 그것은 포인터에 대한 포인터입니다.

  1. lineptr 배열의 다음 요소를 가리 키도록 증가됩니다
  2. lineptr++의 결과는 경우 : 후행 연산자 ++가 참조 연산자 *보다 높은 우선 순위를 가지고 있습니다, 그래서 lineptr++에서 일어나는 것은 이것이다 lineptr의 이전 값,
  3. *lineptr++ 그것을 배열 현재 요소의 값 그래서, 역 참조 배열 현재 요소 즉 포인터
012,

따라서 while 루프는 lineptr (각 요소는 char*)으로 지정된 배열의 모든 요소를 ​​반복하고 인쇄합니다.

+0

아,이 말이 맞습니다. 제 질문에 답해 주셔서 감사합니다! –

5

다음과 같은 *lineptr++ 상상하기 쉬울 수 있습니다 :이

*(lineptr++) 

char*의 배열에 대한 포인터는 lineptr[0]에서, 즉, 배열의 다음 요소로 이동, 우리 lineptr[1]으로 이동하십시오. (포인터의 증가는 포인터의 후위 증가로 인해 역 참조 후 발생합니다.)

그래서 기본적으로 다음과 같은 사항이 발생합니다 :

  1. lineptr[0] (유형 char*의) deferencing으로 검색됩니다.
  2. 포인터가 배열의 다음 요소로 증가합니다. 포인터의 후위 증가분
  3. 이제 포인터가 lineptr[1]을 가리키고, 1 단계에서 다시 프로세스를 반복하십시오.
+0

나는 * (lineptr ++)가별로 도움이되지 않는다고 생각한다. 즉, 역 참조가 시작되기 전에 lineptr이 증가합니다. 실제로 일어나는 일은 두 개의 분리 된 작업과 비슷합니다 : * lineptr, ++ lineptr. – Naaff

+0

(* lineptr) ++을 사용하면 참조를 취소 한 다음 증가시킵니다. lineptr는 역 참조로 첫 번째 행을 선택한 다음 포인터를 증가시켜 다음 문자를 가리키는 배열에 대한 포인터입니다. 따라서 라인 포인터가 3 줄로 배열되어 있으면 브라켓 팅은 1, 2, 3 번째 문자부터 시작하여 3 번째 줄을 인쇄합니다. * (lineptr ++)는 세 줄 각각을 인쇄합니다. – stefanB

+0

* (lineptr ++)은 여전히 ​​하나의 명령문이므로 사후 증가가 발생하기 전에 포인터의 역 참조가 발생합니다. 괄호를 추가하면 연산자 우선 순위 만 변경됩니다. 이 경우 Adam Rosenfield의 답변에서 지적한 바와 같이 ++는 *보다 우선 순위가 높으므로 괄호는 해당 단일 문에서 발생하는 두 가지 사항을 시각적으로 표시합니다. – coobird

7

계속 읽기! p의 아주 밑바닥에. 함수 정의 형식 파라미터로

99

char s[]; 

char *s; 

등가이고; 우리는 매개 변수가 포인터임을 명시 적으로 말하기 때문에 후자를 선호합니다.

.l.e. 함수에 배열 (변수가 아님)을 결코 전달할 수 없습니다. 배열을 취하는 것처럼 보이는 함수를 선언하면 실제로는 포인터가 걸립니다 (은 변수입니다). 이것은 의미가 있습니다. 함수 인수가 변수가 아닌 것은 이상합니다. 함수를 호출 할 때마다 다른 값을 가질 수 있으므로 상수가 아닙니다!

+0

글쎄, 함수에 배열 이름을 전달할 수 있습니다. 실제로 포인터를 전달한 것처럼 보이게하는 액션이 ​​있습니다. 말이되는 것보다 대처하는 것 같아요. –

+0

아, 지금 기억합니다. 배열은 함수의 스택 프레임에 복사되지 않고 해당 배열에 대한 포인터 만 복사됩니다. 알림 주셔서 감사합니다! –