我在以下代码中有一个问题,问题简单的问题是,char*的动态分配的阵列的值从行号24变为行号28,我可以'弄清楚为什么
代码:
#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
我期望上部和下部是相同的,而与使用动态分配有一些我不知道的错误,也不是相同的。
返回的指向std::string::c_str
指向的数组归string
拥有。substr
返回一个临时string
对象,该对象在称为substr
的表达式末尾出现。
综合这两个事实意味着,argv
中指向的阵列在创建它们后立即被删除。当您四处打印它们中的任何一个已经死了。
这似乎是一个简单的问题,但实际上并非如此,我花了几个小时才能找到答案。让我们在下面查看此代码:
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
在{}范围内运行时,P和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
也许有些奇怪。但是我不确定。我会继续检查。而且,如上所述,P1和P1指向不同的临时变量,根据不同的输出,P和P1可能指向第一个示例中相同的临时变量。让我们回到您的代码中,char **是指针的指针,经常将指针指向临时变量是错误的。我的建议是,您可以使用string
的数组而不是指针数组。希望会有所帮助。
您没有为创建的临时子弦字符串对象分配任何东西,该对象创建了一个临时指针。
做类似的事情应该有效,但不会推荐,因为您无法释放该记忆:
argv[argc] =(char*)((new string(x.substr(i,k)))->c_str());
您需要字符串对象才能生存,因为C_STR返回一个恒定指针,指向字符串对象的值。如果字符串对象不存在,那指针指的是什么?阅读以下内容:c_str cplusplus.com
建议将子弦存储到某些数组/向量,然后与指针进行必要的工作。
@mohamed Ibrahim,我认为我已经得到了两个输出不同的问题的真正原因。首先让我们考虑一个问题:
临时变量结束其寿命时发生了什么?
请参阅此代码:
int a1 = 9;
int& a = a1;
{
int b = 10;
a = b;
cout << a << endl;
int c = 11;
count << a << endl;
}
cout << a << endl;
其输出是:
10
11
11
但是,众所周知,当我们尝试在最后一次打印'a'
时,'b'
和'c'
已经消失了。为什么" a"仍然具有值?
原因是尽管'b'
和'c'
已经消失了,'b'
和'c'
的内存和数据仍然存在。'a'是参考,它指的是'b'
和'c'
的内存。
让我们继续考虑:
何时会扫除临时变量的内存和数据?
即使是临时寿命也已经结束,但是它的内存和数据仍然存在,直到声明另一个临时变量为止,新变量的值涵盖了该内存中的旧变量,然后所有的指针和所有指针和提及旧变量的引用,其价值已更改,我们可以将其价值打印出来以证明。因此,在您的代码中,尽管您可以打印出正确的值,但在每个循环中都会声明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;
}
上面的代码可以很好地工作,但是它不安全,我不喜欢这种编码方式。正如我所说的那样,我的建议不要试图将指针指向一个临时变量,从不这样做。没有犯罪,请更正您的代码。