2014-10-07 3 views
0

쉘을 만들려고 시도한 후에 나는 약간의 도움을 요청합니다. 필자는 다른 데이터 구조로 4 번이나 시작하여 아래의 문제에 대한 해결책을 제시했습니다. 나는 개별적인 인자를 깨고 그것에 대한 포인터가 필요한 문자열을 가지고있다. 내가 재미있는 결과를 얻고 제대로 인수를 채울 것 질수 있기 때문에 내가 궁극적으로 간부 인 함수에 인수를 전달하지만, 여기의 단순화 된 버전입니다const 캐스팅을 사용하여 std 문자열을 char *로 변환

char* args[100]; 
int counter=0; 
string temp = "some text and stuff here"; 
stringstream s (temp); 
while(s>> temp) 
{ 
    cout << "TOKEN " << counter << " =" << temp <<endl; 
    args[counter]=const_cast<char *> (temp.c_str()); 
    counter++; 
} 
//print the debug info 
     for(int ii=0; args[ii] != NULL; ii++) 
    { 
     cout << "Argument OUT " << ii << ": " << args[ii] << endl; 
    } 

일어나는 뭐죠이 코드는 작동하지 않고 그 이유를 파악하지 못할 . 결과는 args의 모든 값에 "here"를 저장하지만 카운터는 변경됩니다.

TOKEN 0 =some 
TOKEN 1 =text 
TOKEN 2 =and 
TOKEN 3 =stuff 
TOKEN 4 =here 
Argument OUT 0: here 
Argument OUT 1: here 
Argument OUT 2: here 
Argument OUT 3: here 
Argument OUT 4: here 
+0

를 실행할 수 있습니다! –

+1

@NeilKirk const-ness 문제는 모두 같은 장소를 가리키는 포인터와 관련이 없습니다. 'const * cast'는 전달 된 문자열을 변경하지 않더라도'exec *()'함수 패밀리가 필요하기 때문에 non-const 포인터가 필요합니다. 그것은 문제를 일으키는 동일한'std :: string' 객체를 재사용하는 것입니다. – cdhowie

답변

1

아마도 temp 개체가 내부 할당을 다시 사용하고 있기 때문일 수 있습니다. c_str() 결과를 저장하면 메모리 주소 만 저장됩니다. std::string 클래스는 문자열 스트림에서 코드를 읽을 때마다 완전히 새로운 할당을 생성하지 않고 이미 할당 된 코드를 다시 사용합니다 (가능한 경우).

또한, c_str()에 의해 반환 된 포인터를 사용하여 당신은 정의되지 않은 동작을 호출를 제공 한 std::string 객체에 어떤 다른을 수행 한 후.

가능한 경우 argsstd::vector<std::string>으로 변경하십시오. 이것이 가능하지 않다면 strdup() 포인터는 c_str()에 의해 반환되어야합니다. 그 순간에 문자열의 값을 복사하는 완전히 새로운 할당을 생성해야합니다. 물론 완료되면 할당을 free()까지 기억해야합니다.

또한 const 한정자를 버리고 포인터에 쓰면 정의되지 않은 동작이 발생합니다. 최소한 argsconst char * args[100];으로 변경해야하지만 대신 문자열 대신 벡터를 사용하는 것이 좋습니다.

는 정의되지 않은 동작이다. 당신이 포인터 대 char의 배열을 필요로하는 것처럼


exec()를 사용할 필요가 있음을 나타내는 귀하의 의견을 바탕으로 들린다. 그러나 벡터를 사용하여이 작업을 수행 할 수 있습니다. std::string 개체를 보유하려면 하나의 벡터가 필요하며 이는 char* 할당을 소유하게됩니다. 그런 다음 다른 벡터를 사용하여 실제 포인터를 저장할 수 있습니다. 이런 식으로 뭔가 :

const char * binaryPath = "/bin/foo"; 

std::vector<std::string> argStrings; 
std::vector<char *> argPointers; 

std::string temp = "some text and stuff here"; 
istringstream s(temp); 

// argv[0] should always contain the binary's path. 
argPointers.push_back(binaryPath); 

while (s >> temp) { 
    argStrings.push_back(temp); 

    std::cout << "TOKEN " << argStrings.size() 
       << " =" << argStrings.back() << std::endl; 

    // We cast away the const as required by the exec() family of functions. 
    argPointers.push_back(const_cast<char *>(argStrings.back().c_str())); 
} 

// exec() functions expect a NULL pointer to terminate the arguments array. 
argPointers.push_back(nullptr); 

// Now we can do our exec safely. 
execv(binaryPath, &argPointers[0]); 

이 경우 argStrings에서 실제 문자열 할당을 소유하고, 우리는 우리가 execv()에 전달됩니다 포인터의 배열을 개최 argPointers을 사용하고 있습니다. const_castexecv()이 문자열을 수정하지 않기 때문에 안전합니다. (인수는 구형 C 코드와의 호환성을 위해 char * const []이며, 함수는 인수가 const char * const [] 인 것처럼 동작합니다.

+0

벡터가 지금가는 길입니다. 고마워요. 벡터로 변경하면 exec 시스템 호출에 전달할 수 있도록 벡터에 대한 args 포인터를 업데이트해야합니다. 인수를 변환해야하기 때문에 args가 const char * [100]이되기를 원합니다. (아마도 char ** args와 같은 것)? –

+0

@ChaseCollisParker 흠, 기존 API와 일치해야하기 때문에 좀 더 까다 롭습니다. 이것은 사용중인 특정 exec 호출에 따라 달라집니다 (인수 유형이 다양하게 많습니다). 원한다면 우리는 SO 채팅에 대해 더상의 할 수 있습니다. – cdhowie

+0

@ChaseCollisParker 업데이트 된 답변보기 – cdhowie

2

당신이 할 때 : 당신은 그 내용에 대한 포인터를 저장, 문자열을 복사하지 않습니다

args[counter]=const_cast<char *> (temp.c_str()); 

. 따라서 그들은 모두 동일한 temp 문자열을 가리키며,이 문자열은 인쇄 할 때 값을 모두 동일하게 만듭니다.

argsstd::vector<std::string>을 방금 사용하면 훨씬 쉬울 것입니다.

0

임시 객체에 대한 포인터를 저장하는 것은 이동 방법이 아닌 각 문자열을 별도로 저장해야합니다. 예 :

#include <iostream> 
#include <vector> 
#include <sstream> 

using namespace std; 

void exec(char* args[]) 
{ 
    for (int i = 0; args[i] != NULL; ++i) 
     cout << args[i] << endl; 
} 

int main() 
{ 
    string temp = "some text and stuff here"; 
    stringstream s (temp);  

    vector<string> tokens; 
    while(s>> temp) 
    { 
    tokens.push_back(temp); 
    } 

    int counter = 0; 
    char *args[100]; 
    for (auto it = tokens.begin(); it != tokens.end(); ++it) 
    args[counter++] = const_cast<char*>(it->c_str()); 
    args[counter] = NULL; 

    exec(args); 

    return 0; 
} 

당신은 그것을 here 이유에 대한 가리키는 const 포인터를 반환 c_str

관련 문제