2017-04-26 5 views
-2

다음 코드 조각에 문제가 있습니다. 문제는 단순히 동적으로 할당 된 char * 배열의 값이 행 번호 24에서 행 번호 28로 변경되어서 숫자를 변경할 수 없다는 것입니다. 밖으로 왜C++ 동적 할당 char *

코드 :

#include <iostream> 
#include <string> 
#include <stdlib.h> 
#include <ctype.h> 
#include <cstring> 

using namespace std; 

int main() { 
    string x = "5+90-88n"; 
    unsigned int i =0, k=0, argc=0; 
    char** argv = new char*[x.length()]; 

    while (i < x.length()) { 
    if (isdigit(x[i])) { 
     k=0; 
     while (isdigit(x[i+k])) {k++;} 
     argv[argc] = (char*)x.substr(i,k).c_str(); 
     i+=k; 
    } else { 
     argv[argc] = (char*)x.substr(i,1).c_str(); 
     i++; 
    } 
    cout << argc <<" "<< argv[argc] <<endl; 
    argc++; 
    } 

    cout << " ------ \n"; 
    for (unsigned int kk =0; kk<argc; kk++) { 
    cout << kk << " " << argv[kk] << endl; 
    } 

    return 0; 
} 

출력 :

0 5 
1 + 
2 90 
3 - 
4 88 
5 n 
------ 
0 n 
1 n 
2 n 
3 n 
4 n 
5 n 

심지어 약간의 실수가 같은 의미없는 것, 동일로 상부 및 하부 부품을 기다리고 있었다 나는 알았지 않거나 동적 할당을 사용하는 것에 대해 모르는 뭔가가 있습니다.

+1

왜 char * 배열을 사용하고 있습니까? 문자열의 벡터를 사용하십시오. –

+0

벡터가 더 뛰어나다는 것을 알고 있지만 이것은 할당의 일부이기 때문에 할당에서 사용하는 것이 확실치 않습니다. 그러나 위의 부분은 주된 문제를 일으킬 것입니다. –

+0

* 포인터 *에는 메모리를 할당하지만 문자열에는 할당하지 않습니다. –

답변

2

std::string::c_str의 포인터가 가리키는 배열은 string에 의해 소유됩니다. substrsubstr이 호출 된 표현식의 끝 부분에서 범위를 벗어나는 임시객체를 반환합니다.

이 두 사실을 종합하면 포인터를 가리키는 배열이 argv에 있음을 의미합니다. 당신이 그 중 어느 하나를 인쇄 할 때가되면 그들은 오래 전에 죽었습니다.

0

단순한 문제인 것처럼 보이지만 실제로는 그렇지 않습니다. 답을 찾으려고 몇 시간이 걸렸습니다.

int main() 
{ 
    const char* p; 
    const char* p1; 
    { 
    string x = "xt"; 
    p = x.substr(0, 1).c_str(); 
    cout << p << endl; 
    p1 = x.substr(1, 1).c_str(); 
    cout << p1 << endl; 
} 
cout << p << endl; 
cout << p1 << endl; 
return 0; 
} 

출력은 다음과 같습니다 : 우리가 아래 코드를 보자

x 
t 
t 
t 

은 {} 범위 페이지에서 실행 및 P1은 임시 변수를 가리키고, 지금은 이러한 변수가 존재하는, 그래서 p1을 출력 할 수 있습니다. {} 범위를 벗어나는 코드가 존재할 때, 그 임시 변수는 존재하지 않지만 다시 참조 할 수는 없지만 메모리와 데이터는 여전히 존재합니다. 그래서 메모리 충돌없이 p와 p1의 값을 출력 할 수 있습니다. 그러나 p와 p1의 값이 같은 이유는 무엇입니까? 우리는이를 보자 :

int main() 
{ 
    const char* p; 
    const char* p1; 
    { 
    string x = "xt"; 
    string t1 = x.substr(0, 1); 
    p = t1.c_str(); 
    cout << p << endl; 
    string t2 = x.substr(1, 1); 
    p1 = t2.c_str(); 
    cout << p1 << endl; 
} 
cout << p << endl; 
cout << p1 << endl; 
return 0; 
} 

그것의 출력은 다음과 같습니다

x 
t 
x 
t 

를 예상대로. 어쩌면 substr과 함께 이상한 것이있을 수 있습니다. 그러나 나는 그것에 대해 확신하지 못한다. 나는 계속 점검 할 것이다. 그리고 위의 코드에서 볼 수 있듯이 p와 p1은 서로 다른 임시 변수를 가리키고 있습니다. 서로 다른 결과에 따라 p와 p1은 첫 번째 예에서 동일한 임시 변수를 가리킬 수 있습니다. 코드로 돌아가 보자. char **는 포인터에 대한 포인터이다. 포인터를 임시 변수를 가리키는 포인터로 자주 만드는 것은 잘못이다. 제안 사항은 포인터 배열 대신 string 배열을 사용할 수 있습니다. 도움이 되길 바랍니다.

+0

이 답변을 주셔서 감사합니다.하지만 정말로 ' 두 코드 사이의 핵심 차이를 얻으십시오 –

+0

첫 번째 예에서는 substr()에 의해 임시 문자열이 작성되고, 두 번째 예에서는 임시 변수의 값을 취하도록 t1과 t2를 선언합니다. 그것이 차이점입니다. –

+0

나는 이런 식으로했습니다 : 문자열 y1, y2, x = "5 + 90-88n"; 다음 : y1 = x.substr (i, k); argv [argc] = (char *) y1.c_str(); 그리고 y2와 동일합니다. 다른 결과가 나왔지만 문제는 여전히 그대로 있습니다. –

0

배열에 대한 임시 포인터를 만드는 임시 하위 문자열 문자열 개체에 대해 할당하지 않습니다.

이 같은 일을해야 이렇게하지만 당신은 더 이상 그 메모리를 확보 할 수 없기 때문에 권장하지 않습니다 : 당신은 c_str 문자열 객체의 값을 상수 포인터를 반환으로 살아 남기 위해 문자열 객체가 필요

argv[argc] =(char*)((new string(x.substr(i,k)))->c_str()); 

을 . 문자열 객체가 존재하지 않는다면 그 포인터는 무엇을 가리키고 있을까요? 읽기 : c_str cplusplus.com

일부 배열/벡터에 하위 문자열을 저장 한 다음 포인터로 필요한 작업을 수행하는 것이 좋습니다.

0

@ 모하메드 이브라힘 (Mohamed Ibrahim), 저는이 문제의 실제적인 이유가 두 가지 출력이 다르다고 생각합니다. 처음에 하나의 문제를 고려해 보겠습니다.

임시 변수의 수명이 다 된 경우 어떻게됩니까? 우리가 지난 시간에 밖으로 'a'를 인쇄 할 때

10 
11 
11 

을하지만 우리가 아는 한, 'b''c'는 간 :

int a1 = 9; 
int& a = a1; 
{ 
    int b = 10; 
    a = b; 
    cout << a << endl; 
    int c = 11; 
    count << a << endl; 
} 
cout << a << endl; 

출력은 다음과 같습니다

이 코드를 참조하십시오. 'a'가 여전히 가치가있는 이유는 무엇입니까?

이유는 'b''c' 여전히 갈 'b''c'에도 불구하고 기존됩니다의 메모리와 데이터입니다. 'a'는 참조 용이며 메모리는 'b'이고 'c'입니다.

때 메모리와 임시 변수의 데이터를 휩쓸됩니다

은 우리가 고려 계속하자?

임시 수명도 끝났지 만 다른 임시 변수가 선언 될 때까지 메모리와 데이터는 여전히 존재하며 새로운 varialbe의 값은 해당 메모리의 이전 변수 값을 포함합니다. 포인터 및 이전 변수를 참조하는 참조가 변경되어 값이 변경되면 값을 출력하여 증명할 수 있습니다. 그래서 올바른 값을 출력 할 수 있지만 새로운 변수가 이전 코드를 덮어 썼음에도 불구하고 코드에서 string의 새 임시 변수가 각 루프에 선언됩니다. while 범위가 끝난 후에는 단 하나의 변수 값만 존재하며, 선언 한 마지막 변수이며 나머지는 모두 덮여 있습니다. 그래서 우리는 마지막 출력에서 ​​같은 값을 볼 수있었습니다.

모든 값을 유지하는 방법은 전역 변수에 저장하는 것입니다 위의 코드가 잘 작동 할 수

int main() 
{ 
    string x = "5+90-88n"; 
    unsigned int i =0,k=0,argc=0; 
    char** argv = new char*[x.length()]; 

    while (i< x.length()) 
{ 
    if (isdigit(x[i]))   { k=0; 
         while(isdigit(x[i+k])) {k++;} 
         char* temp = (char*)x.substr(i,k).c_str(); 
         argv[argc] = new char[strlen(temp) + 1]; 
         memset(argv[argc], 0, sizeof(argv[argc])); 
         strcpy(argv[argc], temp); 
         i+=k; 
        } 
    else    { 
        char* temp = (char*)x.substr(i,1).c_str(); 
         argv[argc] = new char[strlen(temp) + 1]; 
         memset(argv[argc], 0, sizeof(argv[argc])); 
         strcpy(argv[argc], temp); 
        i++; 
        } 
cout << argc <<" "<< argv[argc] <<endl; 
argc++; 
} 
cout<<" ------ \n"; 
for(unsigned int kk =0;kk<argc;kk++) { cout <<kk <<" "<<argv[kk]<<endl; } 

return 0; 
} 

하지만 안전하지 않은, 내가 코딩이 방법을 좋아하지 않는다. 필자가 말했듯이, 포인터가 임시 변수를 가리 키도록 시도하지 마십시오. 그렇게하지 마십시오. 범죄는 아닙니다. 코드를 수정하십시오.