scanf로 문자열 읽기


147

나는 무언가에 대해 약간 혼란스러워합니다. 나는 C 문자열을 읽는 올바른 방법 scanf()

(가능한 버퍼 오버플로를 염두에 두지 말고 간단한 예일뿐입니다)

char string[256];
scanf( "%s" , string );

그러나 다음과 같이 작동하는 것 같습니다.

scanf( "%s" , &string );

이것은 내 컴파일러 (gcc), 순수한 운 또는 다른 것입니까?


두 번째 경우에는 해당 버퍼를 전혀 사용하지 않기 때문에 실제로 가능한 버퍼 오버플로가 없습니다. 또는 3자를 초과하는 문자열이 "버퍼"를 오버플로한다고 말할 수 있습니다.
TED

첫 번째 예를 언급하고있었습니다. 또한 다른 사람들은 이미 여기서 무슨 일이 일어나고 있는지 지적했습니다.
abeln

예. 그것을 시험해 보니 Gareth가 옳습니다. 기묘한.
TED

이 질문은 "scanf로 문자열을 읽는 방법"에 대한 검색에 의해 반환되므로이 질문은 포인터를 버퍼에 전달하는 방법에 관한 scanf것이며 질문과 허용 된 답변 모두에 중점을 두는 것이 적절할 수 있습니다 . 실제 코드에서 사용해야하는 최대 입력 길이에 대해 매우 중요한 제한을 생략합니다 (그러나이 질문의 요점은 제외).
Arkku

답변:


141

배열은 첫 번째 요소에 대한 포인터로 "부패"하므로 scanf("%s", string)에 해당합니다 scanf("%s", &string[0]). 반면에 scanf("%s", &string)pointer-to-를 전달 char[256]하지만 같은 위치를 가리 킵니다.

그런 다음 scanf인수 목록의 꼬리를 처리 할 때을 꺼내려고합니다 char *. string또는에 전달했을 때 올바른 &string[0]것이지만, 전달 했을 때 &string언어 표준이 보장하지 않는 것, 즉 포인터 &string&string[0]-가 다른 유형과 크기의 객체에 대한 포인터에 의존하고 있습니다. 같은 장소에서 시작-같은 방식으로 표현됩니다.

나는 그것이 작동하지 않는 시스템을 만난 적이 있다고 생각하지 않으며 실제로는 아마 안전합니다. 그보다 적은 것은 틀 렸으며 일부 플랫폼에서는 실패 할 수 있습니다. (가설의 예 : 모든 포인터와 함께 유형 정보를 포함하는 "디버깅"구현. Symbolics "Lisp Machines"에 대한 C 구현은 이와 같은 방식으로 생각 합니다.)


5
+1. 또한 어레이 붕괴 &stringstring(다른 응답이 잘못 주장한 것처럼 임의의 메모리 손상을 초래하는 대신) 다음과 동일한 방식으로 작동 하는지 확인하는 것은 사소한 일입니다 .printf("%x\n%x\n", string, &string);
Josh Kelley

@ 조쉬 켈리 (Josh Kelley)는 malloc ()을 통해 할당 된 문자열에 대한 포인터가 아닌 경우가 아니라고 생각합니다.
abeln

4
@abeln : 맞습니다. malloc ()을 통해 할당 된 문자열의 string경우 포인터 &string이며 해당 포인터의 주소이므로 둘은 서로 호환되지 않습니다. 가레스도 배열 붕괴의 경우에, 설명, 따라 string&string동일한 유형 (그들은 대부분의 아키텍쳐에 대한 상호 교환 될 일이 있더라도) 기술적으로, 그리고 당신이 켜있는 경우 GCC는 두 번째 예를 들어 경고를 줄 것이다 -Wall.
Josh Kelley

@ 조쉬 켈리 (Josh Kelley) : 고마워요.
abeln

1
@JCooper str, & str [0]은 모두 같은 것을 나타내며 (배열의 시작) 반드시 & str도 같은 메모리 주소는 아닙니다. 이제 strPtr은 str을 가리 키므로 strPtr 내부에 저장된 메모리 주소는 str 및 12fe60과 같습니다. 마지막으로 & strPtr은 변수 strPtr의 주소이며, strptr에 저장된 값이 아니라 strPtr의 실제 메모리 주소입니다. strptr은 다른 변수 들과는 다른 변수이기 때문에 다른 메모리 주소도 가지고 있습니다.이 경우 12fe54
Juan Besa

-9

나는 이것이 아래에 정확하고 도움이 될 것이라고 생각합니다. 오류가 있으면 언제든지 수정하십시오. 저는 C에서 처음입니다.

char str[]  
  1. 메모리에 자체 주소가있는 char 유형의 값 배열
  2. 배열의 요소만큼 연속 된 주소를 메모리에 자체 주소를 갖는 char 유형의 값 배열
  3. 종단 NULL 문자 등 '\0' &str, &str[0]str, 세 개의 어레이의 첫 번째 요소의 주소가 메모리의 동일한 위치를 나타낸다str

    char * strPtr = & str [0]; // 선언 및 초기화

또는 이것을 두 가지로 나눌 수 있습니다.

char *strPtr; strPtr = &str[0];
  1. strPtr 에 대한 포인터입니다 char
  2. strPtr 배열의 포인트 str
  3. strPtr 메모리에 자체 주소를 가진 변수입니다
  4. strPtr 주소 값을 저장하는 변수입니다 &str[0]
  5. strPtr 메모리의 자체 주소가 저장 한 메모리 주소와 다릅니다 (메모리의 어레이 주소는 & str [0]).
  6. &strPtr strPtr 자체의 주소를 나타냅니다

포인터에 대한 포인터를 다음과 같이 선언 할 수 있다고 생각합니다.

char **vPtr = &strPtr;  

strPtr 포인터의 주소로 선언하고 초기화합니다

또는 두 가지로 나눌 수 있습니다.

char **vPtr;
*vPtr = &strPtr
  1. *vPtr strPtr 포인터의 포인트
  2. *vPtr 메모리에 자체 주소를 가진 변수입니다
  3. *vPtr & strPtr 주소 값을 저장하는 변수입니다.
  4. 최종 의견 : 당신은 할 수 없습니다 str++, str주소는입니다 const, 그러나 당신은 할 수 있습니다strPtr++
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.