sourcecode

char*str={"foo",...의 차이점은 무엇입니까?} 그리고 charstr[5]={"foo",...} 배열 정의?

codebag 2023. 11. 4. 10:39
반응형

char*str={"foo",...의 차이점은 무엇입니까?} 그리고 charstr[5]={"foo",...} 배열 정의?

사례 1: 글을 쓸 때

char*str={"what","is","this"};

그리고나서str[i]="newstring";반면에 유효합니다.str[i][j]='j';유효하지 않습니다.

사례 2: 글을 쓸 때

char str[][5]={"what","is","this"};

그리고나서str[i]="newstring";반면에 유효하지 않습니다.str[i][j]='J';유효합니다.

그것은 왜 그럴까?저는 이미 다른 답을 읽고 많이 혼란스러워 하는 초보자입니다.

우선: 제안: 배열은 포인터가 아니며반대도 마찬가지입니다!!

그건 그렇지만, 이 특정한 시나리오를 깨우치기 위해서는

  • 첫번째 경우에는

    char*str={"what","is","this"};
    

    당신이 생각하는 것처럼 행동하지 않습니다.이는 §6.7.9/P2장에 따라 C 구현에 적합한 진단을 요구하는 제약 조건 위반입니다.

    초기화자는 초기화 중인 엔티티 내에 포함되지 않은 개체에 대한 값을 제공하려고 시도해서는 안 됩니다.

    경고를 활성화하면 (적어도)

    경고: 스칼라 이니셜라이저의 요소 초과

      char*str={"what","is","this"};
    

    그러나 엄격한 호환성이 설정된 컴파일러는 코드 컴파일을 거부해야 합니다.컴파일러가 바이너리 컴파일과 생성을 선택한 경우, 동작은 C 언어의 정의 범위에 있지 않고 컴파일러 구현에 달려 있습니다.

    이 경우 컴파일러는 이 문장을 기능적으로만 동일하게 만들기로 결정했습니다.char*str= "what";

    자, 자, 여기.strA를 가리키는 포인터입니다.char, 문자열 리터럴을 가리킵니다.포인터에 다시 할당할 수 있습니다.

    str="newstring";  //this is valid
    

    하지만, 이런 식의 진술.

     str[i]="newstring";
    

    유효하지 않습니다. 여기서 포인터 유형을 변환하여 저장하려고 시도합니다.chartype(유형이 호환되지 않는 경우).컴파일러는 이 경우 잘못된 변환에 대한 경고를 던져야 합니다.

    그 후에 다음과 같은 진술이.

    str[i][j]='J'; // compiler error
    

    배열 구독을 사용하는 경우 구문적으로 유효하지 않습니다.[]"개체 유형을 완료할 pointer"가 아닌 것에 연산자를 지정합니다.

    str[i][j] = ...
          ^^^------------------- cannot use this
    ^^^^^^ --------------------- str[i] is of type 'char', 
                                 not a pointer to be used as the operand for [] operator.
    
  • 반면에 번째 경우에는

    str는 배열의 배열입니다.개별 배열 요소를 변경할 수 있습니다.

     str[i][j]='J'; // change individual element, good to go.
    

    배열에 할당할 수 없습니다.

     str[i]="newstring";  // nopes, array type is not an lvalue!!
    

  • 마침내. (댓글에서 볼 수 있듯이) 당신이 글을 쓰려고 했던 것을 고려할 때.

    char* str[ ] ={"what","is","this"};
    

    첫 번째 경우에는 어레이 홀드에 대한 논리가 동일합니다.이거는.str한 줄 한 줄의 포인터배열 구성원들은 할당이 가능합니다.

    str[i]="newstring";  // just overwrites the previous pointer
    

    완벽하게 괜찮습니다.그러나 배열 멤버로 저장된 포인터는 문자열 리터럴에 대한 포인터이므로 위에서 언급한 것과 같은 이유로 문자열 리터럴에 속하는 메모리의 요소 중 하나를 수정하려는 경우 정의되지 않은 동작을 호출합니다.

     str[i][j]='j';   //still invalid, as above.
    

메모리 레이아웃이 다릅니다.

char* str[] = {"what", "is", "this"};

    str
+--------+      +-----+
| pointer| ---> |what0|
+--------+      +-----+   +---+
| pointer| -------------> |is0|
+--------+                +---+    +-----+
| pointer| ----------------------> |this0|
+--------+                         +-----+

이 메모리 레이아웃에서,str는 개별 문자열에 대한 포인터의 배열입니다.일반적으로 이러한 개별 문자열은 정적 저장소에 상주하며, 문자열을 수정하려고 하면 오류가 발생합니다.그래픽에서 제가.0종료 Null 바이트를 나타냅니다.

char str[][5] = {"what", "is", "this"};

  str
+-----+
|what0|
+-----+
|is000|
+-----+
|this0|
+-----+

이 경우에는.str는 스택에 위치한 연속된 2D 문자 배열입니다.배열을 초기화할 때 문자열이 이 메모리 영역에 복사되고 개별 문자열은 0바이트로 패딩되어 배열에 규칙적인 모양을 제공합니다.

이 두 메모리 레이아웃은 근본적으로 서로 호환되지 않습니다.포인터가 다른 함수에 연결될 것으로 예상되는 함수는 둘 중 하나를 전달할 수 없습니다.그러나 개별 문자열에 대한 액세스는 호환됩니다.당신이 글을 쓸때str[1], 당신은.char*바이트를 포함하는 메모리 영역의 첫 번째 문자로is0, C열

첫 번째 경우에는 이 포인터가 단순히 메모리에서 로드된 것임이 분명합니다.두 번째 경우에는 배열-포인터-디케이를 통해 포인터가 생성됩니다.str[1]실제로는 정확히 5바이트의 배열을 나타냅니다. (is000), 거의 모든 컨텍스트에서 첫 번째 요소에 대한 포인터로 즉시 디코딩됩니다.그러나 배열-포인터-디케이에 대한 완전한 설명은 이 답변의 범위를 벗어난다고 생각합니다.궁금하다면 구글 배열 포인터 붕괴.

처음으로 당신은 a에 대한 포인터인 변수를 정의합니다.char, 보통 하나의 끈으로 사용됩니다.문자열 리터럴을 가리키도록 포인터를 초기화합니다."what". 컴파일러는 목록에 이니셜이 너무 많다고 불평해야 합니다.

두 번째 정의는 다음을 만듭니다.str다섯 개씩 세 줄로 늘어선 배열.char. 즉, 세 개의 다섯 글자로 이루어진 문자열의 배열입니다.


조금 다르게 보면 다음과 같은 것을 볼 수 있습니다.

첫 번째 경우:

+-----+     +--------+| str | --> | "뭐" |+-----+     +--------+

그리고 잠시동안 당신은

+--------+--------+--------+| "What" | "is" | "this" |+--------+--------+--------+

또한 첫 번째 버전의 경우 단일 문자열에 대한 포인터를 사용하면 식이str[i] = "newstring"또한 단일 요소에 포인터를 할당하려고 할 때 경고로 이어져야 합니다. str[i].

이 할당은 두 번째 버전에서도 유효하지 않지만 다음과 같은 또 다른 이유로 유효하지 않습니다.str[i]는 배열(5개의 배열)입니다.charelements)을(를) 할당할 수 없으며 배열에 복사만 할 수 있습니다.그래서 네가 해볼 수 있게,strcpy(str[i], "newstring")컴파일러는 불평하지 않을 겁니다그러나 10자(터미네이터 기억)를 5자 배열로 복사하려고 하면 범위를 벗어나서 정의되지 않은 동작으로 이어지기 때문에 잘못된 것입니다.

  • 첫번째 선언에서

    char *str={"what","is","this"}; 
    

    선언합니다str의 지시자.char스칼라입니다.표준은 다음과 같이 말합니다.

    6.7.9 초기화 (p11):

    스칼라의 이니셜라이저는 선택적으로 괄호로 둘러싸인 단일 식이어야 합니다. [...]

    그것은 스칼라 유형이 하나의 식으로 묶은 초기화기를 가질 수 있지만 다음과 같은 경우에

    char *str = {"what","is","this"}; // three expressions in brace enclosed initializer
    

    이것을 어떻게 처리할지는 컴파일러들에게 달려있습니다.나머지 이니셜라이저에 발생하는 문제는 버그입니다.컨펌 컴플라이어는 진단 메시지를 제공해야 합니다.

    [Warning] excess elements in scalar initializer   
    

    5.1.1.3 진단(P1):

    동작 또한 명시적으로 정의되지 않았거나 구현이 정의된 것으로 명시적으로 지정된 경우에도, 사전 처리 번역 유닛 또는 번역 유닛이 어떤 구문 규칙 또는 제약 조건의 위반을 포함하는 경우, 적합한 구현은 (구현이 정의된 방식으로 식별된) 적어도 하나의 진단 메시지를 생성해야 합니다.

  • "str[i]="newstring"; 유효하지만 "는 유효하지 않습니다."

    str[i]char타이핑하고 a만 보유할 수 있습니다.char자료형.할당중"newstring"(이 중 어느 것에 해당합니다.char *)이(가) 잘못되었습니다.성명서str[i][j]='j';첨자 연산자는 배열 또는 포인터 데이터 형식에만 적용할 수 있으므로 잘못되었습니다.

  • 만들 수 있습니다.str[i]="newstring";선언을 통해 작업str다수의char *

    char *str[] = {"what","is","this"};
    

    이경우str[i]char *type 및 문자열 리터럴을 할당할 수 있지만 문자열 리터럴을 수정할 수 있습니다.str[i]가 정의되지 않은 동작을 호출합니다.당신은 할 수 없다고 했습니다.str[0][0] = 'W'.

  • 토막글

    char str[][5]={"what","is","this"};
    

    선언하다str다양한 정보를 제공할 수 있습니다.chars.str[i]는 사실 배열이고 배열은 수정할 수 없는 l 값이므로 할당 연산자의 왼쪽 피연산자로 사용할 수 없습니다.이거는.str[i]="newstring";무효한.하는 동안에str[i][j]='J';배열의 요소를 수정할 수 있기 때문에 작동합니다.

당신이 다른 대답들이 나를 혼란스럽게 한다고 말한 것만으로, 더 간단한 예를 들어 어떤 일이 일어나고 있는지 먼저 알아보겠습니다.

char *ptr = "somestring";

여기서"somestring"는 메모리의 읽기 전용 데이터 섹션에 저장되는 문자열 리터럴입니다.ptr는 할당된 메모리의 첫 번째 바이트를 가리키는 포인터(같은 코드 섹션의 다른 변수와 마찬가지로 allocated)입니다.

따라서 이 두 진술을 고려하지 않습니다.

char *ptr2 = ptr; //statement 1 OK
ptr[1] = 'a';     //statement 2 error

문 1은 완벽하게 유효한 작업(1개의 포인터를 다른 포인터에 할당)을 수행하고 있지만 문 2는 유효한 작업(읽기 전용 위치에 쓰기 시도)이 아닙니다.

반면에 다음과 같은 글을 쓴다면:

char ptr[] = "somestring";

여기서 ptr은 실제로는 포인터가 아니라 배열의 이름입니다(포인터와 달리 메모리에 추가 공간을 차지하지 않습니다).필요에 따라 동일한 바이트 수를 할당합니다."somestring"(읽을 뿐만 아니라) 그게 다입니다.

따라서 동일한 두 문장과 하나의 추가 문장을 고려합니다.

char *ptr2 = ptr; //statement 1 OK
ptr[1] = 'a';     //statement 2 OK
ptr = "someotherstring" //statement 3 error

문 1은 완벽하게 유효한 작업을 수행하고 있습니다(포인터에 배열 이름을 할당하고 배열 이름은 첫 번째 바이트의 주소를 반환합니다). 문 2도 메모리가 읽기 전용이 아니기 때문에 유효합니다.

문 3은 포인터가 아니므로 유효한 작업이 아니며 다른 메모리 위치를 가리킬 수 없습니다.


이제 이 코드에서,

char **str={"what","is","this"};

*str는 포인터(str[i]와 같은*(str+i))

하지만 이 코드에서는

char str[][] = {"what", "is", "this"};

str[i]는 포인터가 아닙니다.배열의 이름입니다.

위와 같은 것은 다음과 같습니다.

  • 우선은

    char*str={"what","is","this"};
    

    유효한 C 코드도 아니기 때문에 논의하는 것은 의미가 없습니다.어떤 이유에서인지, gcc 컴파일러는 경고만으로 이 코드를 통과시킵니다.컴파일러 경고를 무시하지 마십시오.gcc를 사용할 때는 항상 다음을 사용하여 컴파일해야 합니다.-std=c11 -pedantic-errors -Wall -Wextra.

  • gcc가 이 비표준 코드를 만났을 때 하는 일은 마치 당신이 작성한 것처럼 처리하는 것입니다.char*str={"what"};. 그리고 그 다음은 다음과 같은 것입니다.char*str="what";. 이것은 결코 C 언어로 보장되지 않습니다.

  • str[i][j]은 포인터의 간접화 수준이 한 단계밖에 없는데도 두 번 간접화를 시도하므로 컴파일러 오류가 발생합니다.타자를 치는 것만큼 말이 안 됩니다.

    int array [3] = {1,2,3}; int x = array[0][0];.

  • 사이의 차이점에 관해서는char* str = ...그리고.char str[] = ..., FAQ 참조: char[]와 char*s의 차이점은 무엇입니까?

  • 관련하여char str[][5]={"what","is","this"};경우 배열(2D 배열)을 만듭니다.프로그래머가 제공한 초기화 수에 따라 최내측 치수는 5로 설정되고 최외측 치수는 컴파일러에 의해 자동으로 설정됩니다.이 경우 3의 코드는 다음과 같습니다.char[3][5].

  • str[i]배열 번호를 제공합니다.i배열된 배열로 말입니다.C의 배열은 언어가 그렇게 설계되어 있기 때문에 할당할 수 없습니다.또한 문자열에 대해서는 잘못된 것입니다. FAQ:문자열 값을 올바르게 할당하는 방법은 무엇입니까?


1) 이는 C116.7.9/2의 제약 조건 위반입니다.6.7.9/11 참조.

혼란을 없애기 위해서는 포인터, 배열 및 이니셜라이저를 제대로 이해해야 합니다.C 프로그래밍 초보자들 사이에서 흔한 오해는 배열이 포인터와 같다는 것입니다.

배열은 동일한 유형의 항목 모음입니다.다음의 선언을 고려합니다.

char arr[10];

이 배열은 각각의 유형에 따라 10개의 요소를 포함합니다.char.

이니셜라이저 리스트는 어레이를 편리한 방식으로 초기화하기 위해 사용될 수 있습니다.다음은 배열 요소를 이니셜라이저 목록의 해당 값으로 초기화합니다.

char array[10] = {'a','b','c','d','e','f','g','h','i','\0'};

배열은 할당할 수 없으므로 배열 선언 시에만 이니셜라이저 목록을 사용할 수 있습니다.

char array[10];
array = {'a','b','c','d','e','f','g','h','i','\0'}; // Invalid...

char array1[10];
char array2[10] = {'a','b','c','d','e','f','g','h','i','\0'};
array1 = array2; // Invalid...; You cannot copy array2 to array1 in this manner.

배열을 선언한 후 배열 구성원에 대한 할당은 배열 인덱싱 연산자 또는 그와 동등한 연산자를 통해 수행해야 합니다.

char array[10];
array[0] = 'a';
array[1] = 'b';
.
.
.
array[9] = 'i';
array[10] = '\0';

루프는 배열 구성원에게 값을 할당하는 일반적이고 편리한 방법입니다.

char array[10];
int index = 0;
for(char val = 'a'; val <= 'i'; val++) {
    array[index] = val;
    index++;
}
array[index] = '\0';

char배열은 상수 null terminal인 문자열 리터럴을 통해 초기화될 수 있습니다.char배열:

char array[10] = "abcdefghi";

그러나 다음은 유효하지 않습니다.

char array[10];
array = "abcdefghi"; // As mentioned before, arrays are not assignable

자, 이제 우리가 포인터를...포인터는 일반적으로 같은 유형의 다른 변수의 주소를 저장할 수 있는 변수입니다.

다음과 같은 선언을 생각해 봅니다.

char *ptr;

이것은 유형의 변수를 선언합니다.char *,achar포인팅합니다.즉, A를 가리킬 수 있는 포인터가char변수.

배열과 달리 포인터는 할당할 수 있습니다.따라서 다음이 유효합니다.

char var;
char *ptr;
ptr = &var; // Perfectly Valid...

포인터가 배열이 아니기 때문에 포인터에는 단일 값만 할당될 수 있습니다.

char var;
char *ptr = &var; // The address of the variable `var` is stored as a value of the pointer `ptr`

포인터에 단일 값을 할당해야 하므로 초기화기 수가 1개 이상이므로 다음은 유효하지 않습니다.

char *ptr = {'a','b','c','d','\0'};

이는 제약 조건 위반이지만 컴파일러가 다음을 할당할 수 있습니다.'a'로.ptr나머지는 무시하고 있어요하지만 그 때에도 컴파일러는 경고를 할 것입니다. 왜냐하면 다음과 같은 문자 리터럴은'a'갖고 있다int기본적으로 type을 입력하고 다음 유형과 호환되지 않습니다.ptr어느 것이char *.

이 포인터가 런타임에 역참조된 경우 잘못된 메모리에 액세스하는 런타임 오류가 발생하여 프로그램이 중단됩니다.

예에서:

char *str = {"what", "is", "this"};

다시 말하지만, 이것은 제약 위반이지만, 당신의 컴파일러는 문자열을 할당할 수 있습니다.what로.str나머지는 무시하고 경고만 표시합니다.

warning: excess elements in scalar initializer.

다음은 포인터와 배열에 관한 혼란을 제거하는 방법입니다.일부 컨텍스트에서 배열은 배열의 첫 번째 요소에 대한 포인터로 붕괴될 수 있습니다.따라서 다음이 유효합니다.

char arr[10];
char *ptr = arr;

배열 이름을 사용하여arr라는 과제 표현으로rvalue, 배열은 첫 번째 요소에 대한 포인터로 붕괴되며, 앞의 식은 다음과 같습니다.

char *ptr = &arr[0];

그 것을 기억하라.arr[0]유형의char,그리고.&arr[0]그것의 주소는 유형입니다.char *, 변수와 호환되는 값입니다.ptr.

문자열 리터럴이 상수 null 종결임을 기억하십시오.char arrays, 따라서 다음 식도 유효합니다.

char *ptr = "abcdefghi"; // the array "abcdefghi" decays to a pointer to the first element 'a'

자, 당신의 경우엔char str[][5] = {"what","is","this"};는 각각 5개의 요소를 포함하는 3개의 배열입니다.

배열은 할당할 수 없으므로,str[i] = "newstring";다음과 같이 유효하지 않습니다.str[i]배열이지만,str[i][j] = 'j';다음부터 유효합니다.str[i][j]는 자체적으로 배열이 아니며 할당 가능한 배열 요소입니다.

사례 1:

내가 글을 쓸때

char*str={"what","is","this"};

그리고나서str[i]="newstring";반면에 유효합니다.str[i][j]='j';유효하지 않습니다.

파트 I.I
>> char*str={"what","is","this"};

이 진술서에서,str에 대한 포인터입니다.chartype. 컴파일할 때 다음 문장에 대한 경고 메시지가 표시되어야 합니다.

warning: excess elements in scalar initializer
        char*str={"what","is","this"};
                         ^

경고의 이유는 - 스칼라에 둘 이상의 이니셜라이저를 제공하고 있습니다.
[산술형과 포인터형을 총칭하여 스칼라형이라고 합니다.]

str는 스칼라이며 C Standards#6.7.9p11:

스칼라의 이니셜라이저는 선택적으로 괄호 안에 포함된 단일 식을 사용해야 합니다.

또한 스칼라에 둘 이상의 이니셜라이저를 주는 것은 정의되지 않은 동작입니다.
From C Standards#J.2 정의되지 않은 동작:

스칼라의 이니셜라이저는 단일 식도 아니고 괄호 안에 포함된 단일 식도 아닙니다.

표준에 따라 정의되지 않은 행동이기 때문에 더 이상 논의할 필요가 없습니다.제1부에 대한 토론 중.2부1부.III 가정하에 -char *str="somestring", 더 잘 이해하기 위해서만char *유형.
문자열에 대한 포인터 배열을 만들려는 것 같습니다.저는 두 경우에 대해 이야기한 후 아래에 문자열에 대한 포인터 배열에 대한 간략한 내용을 추가했습니다.

파트 2
>> then str[i]="newstring"; is valid

아니요, 이건 유효하지 않습니다.
호환되지 않는 변환 때문에 컴파일러가 이 문에 경고 메시지를 주고 있음에 틀림없습니다.
부터str에 대한 포인터입니다.char활자. 그러므로,str[i]에 등장인물입니다.i가리킨 대상을 지난 장소들str[str[i] --> *(str + i)].

"newstring"는 문자열 리터럴이고 문자열 리터럴은 포인터로 붕괴됩니다. 단, 배열을 초기화하는 데 사용되는 경우는 제외하고, 유형은char *그리고 여기서 당신은 그것을 a에 할당하려고 합니다.chartype. 따라서 컴파일러는 경고로 보고합니다.

제1부
>> whereas str[i][j]='j'; is invalid.

예, 이것은 유효하지 않습니다.
[](subscript 연산자)는 배열 또는 포인터 피연산자와 함께 사용할 수 있습니다.
str[i]캐릭터와.str[i][j]사용 중임을 의미합니다.[]위에char잘못된 피연산자입니다.따라서 컴파일러가 오류로 보고합니다.

사례 2:

내가 글을 쓸때

char str[][5]={"what","is","this"};

그리고나서str[i]="newstring";반면에 유효하지 않습니다.str[i][j]='J';유효합니다.

제2부
>> char str[][5]={"what","is","this"};

이것은 전적으로 옳습니다.여기서,str2D 배열입니다.컴파일러는 초기화자 수에 따라 첫 번째 차원을 자동으로 설정합니다.인메모리 뷰(in-memory view)str[][5], 이 경우는 다음과 같습니다.

         str
         +-+-+-+-+-+
  str[0] |w|h|a|t|0|
         +-+-+-+-+-+
  str[1] |i|s|0|0|0|
         +-+-+-+-+-+
  str[2] |t|h|i|s|0|
         +-+-+-+-+-+

Initializer 목록에 따라 2D-array의 각 요소가 초기화되고 나머지 요소는 다음과 같이 설정됩니다.0.

제2부
>> then str[i]="newstring"; is not valid

예, 이것은 유효하지 않습니다.
str[i]는 1차원 배열입니다.
C 표준에 따르면 배열은 수정 가능한 l 값이 아닙니다.
C 표준#6.3.2.1p1에서:

lvalue는 개체를 지정할 가능성이 있는 (공백이 아닌 개체 유형이 있는) 표현입니다. 64) 평가할 때 lvalue가 개체를 지정하지 않으면 동작이 정의되지 않습니다.개체가 특정 유형을 가지고 있다고 할 때 유형은 개체를 지정하는 데 사용되는 l 값으로 지정됩니다.수정 가능한 l 값은 배열 유형이 없고, 불완전한 유형이 없으며, 정수된 유형이 없으며, 구조 또는 조합인 경우 정수된 유형이 있는 구성원(모든 포함된 집합 또는 조합의 구성원 또는 요소 포함)이 없습니다.

또한 배열 이름은 연산자 크기의 피연산자인 _Align of operator 또는 unary & operator인 경우를 제외하고 배열 개체의 초기 요소를 가리키는 포인터로 변환합니다.

C 표준#6.3.2.1p3에서:

연산자 크기의 피연산자, _Align of operator 또는 unary & operator가 배열을 초기화하는 데 사용되는 문자열 리터럴인 경우를 제외하고, "array of type" 유형을 가진 식을 배열 개체의 초기 요소를 가리키며 l 값이 아닌 "pointer to type" 유형을 가진 식으로 변환합니다.

부터str이미 초기화되어 있고 다른 문자열 리터럴을 할당할 때ith 한 무리의str, 문자열 리터럴을 포인터로 변환합니다. 이 포인터는 l 값의 유형을 가지고 있기 때문에 할당이 호환되지 않게 됩니다.char유형의 배열 및 r값char *. 따라서 컴파일러가 오류로 보고합니다.

파트 II.III
>> whereas str[i][j]='J'; is valid.

예, 이것은 다음과 같은 조건에서 유효합니다.i그리고.j주어진 배열에 유효한 값입니다.str.

str[i][j]유형의char, 캐릭터를 지정할 수 있습니다.C는 배열 경계를 확인하지 않으며 배열에 액세스하는 것은 다음을 포함하는 정의되지 않은 동작입니다. 이는 프로그래머가 의도한 대로 또는 분할 오류를 정확히 수행하거나 자동으로 잘못된 결과를 생성하거나 어떤 일이 발생할 수 있습니다.


Case 1에서 문자열에 대한 포인터 배열을 만들겠다고 가정합니다.
다음과 같을 것입니다.

char *str[]={"what","is","this"};
         ^^

인메모리 뷰(in-memory view)str다음과 같은 일이 될 것입니다.

      str
        +----+    +-+-+-+-+--+
  str[0]|    |--->|w|h|a|t|\0|
        |    |    +-+-+-+-+--+
        +----+    +-+-+--+
  str[1]|    |--->|i|s|\0|
        |    |    +-+-+--+
        +----+    +-+-+-+-+--+
  str[2]|    |--->|t|h|i|s|\0|
        |    |    +-+-+-+-+--+
        +----+

"what","is"그리고."this"문자열 리터럴 입니다.
str[0],str[1]그리고.str[2]는 각각의 문자열 리터럴에 대한 포인터이며 다른 문자열을 가리킬 수도 있습니다.

그러니, 이건 완벽하게 괜찮습니다.

str[i]="newstring"; 

가정하에i1이니깐str[1]포인터가 이제 문자열 리터럴을 가리킵니다."newstring":

        +----+    +-+-+-+-+-+-+-+-+-+--+
  str[1]|    |--->|n|e|w|s|t|r|i|n|g|\0|
        |    |    +-+-+-+-+-+-+-+-+-+--+
        +----+

하지만 이렇게 해서는 안됩니다.

str[i][j]='j';

()i=1그리고.j=0,그렇게str[i][j]두 번째 문자열의 첫 번째 문자입니다.)

표준에 따르면 문자열 리터럴을 수정하려고 하면 읽기 전용 저장소에 저장되거나 다른 문자열 리터럴과 결합될 수 있기 때문에 정의되지 않은 동작이 발생합니다.

C 표준 #6.4.5p7부터:

이러한 배열의 요소가 적절한 값을 갖는 경우 이들 배열이 구별되는지 여부는 지정되지 않습니다.프로그램이 이러한 배열을 수정하려고 하면 동작이 정의되지 않습니다.


추가:

C 언어에는 네이티브 문자열 유형이 없습니다.C 언어에서 문자열은 null-terminated 문자 배열입니다.배열과 포인터의 차이를 알아야 합니다.

어레이, 포인터, 어레이 초기화에 대한 이해를 높이기 위해 다음을 읽어보시기 바랍니다.

  1. 배열 초기화, 확인합니다.
  2. 포인터와 배열의 등가성, 이것이것을 확인하세요.

case 1 :

char*str={"what","is","this"};

먼저 위의 문장은 유효하지 않습니다. 경고를 제대로 읽으십시오.str는 단일 포인터이며, 다음을 가리킬 수 있습니다.single하지 않을 때 한 번에 char 배열multiple문자 배열

bounity.c:3:2: warning: scalar initializer의 초과 요소 [기본적으로 활성화]

strchar pointer그리고 그것은 저장되어 있습니다.sectionRAM의 섹션이지만.contents에 저장됩니다.code(Can't modify the contentRAM의 섹션은 다음과 같습니다.str로 초기화됩니다.string(in GCC/linux).

str[i]="newstring";은 유효한 반면 str[i][j]='j';은 유효하지 않습니다.

str= "new string"코드/읽기 전용 섹션을 수정하지 않습니다. 여기서는 단순히 할당합니다.new address로.str그렇기 때문에 유효하지만.

*str='j'아니면str[0][0]='j'여기서 읽기 전용 섹션을 수정하고 다음의 첫 글자를 변경하려고 하므로 유효하지 않습니다.str.

사례 2:

char str[][5]={"what","is","this"};

여기서str2D배열, 즉str그리고.str[0],str[1],str[2]그 자체가 저장됩니다.stack sectionRAM그 말은 당신이 각각을 바꿀 수 있다는 것을 의미합니다.str[i]내용물.

str[i][j]='w';가능한 섹션 내용을 쌓기 위해 노력하고 있기 때문에 유효합니다.

str[i]= "new string";그건 불가능해요 왜냐하면str[0]배열과 배열 자체가 상수 포인터(주소를 변경할 없음)이므로 새 주소를 할당할 수 없습니다.

단순히 첫번째 경우에 str="new string"valid왜냐면strpointer, 조금도 아닌array그리고 두번째 경우에는 str[0]="new string"not valid왜냐면strarray한푼도pointer.

도움이 되었으면 좋겠습니다.

언급URL : https://stackoverflow.com/questions/48315523/what-is-the-difference-between-charstr-foo-and-char-str5-foo

반응형