char *的C 动态分配



我在以下代码中有一个问题,问题简单的问题是,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;
}

上面的代码可以很好地工作,但是它不安全,我不喜欢这种编码方式。正如我所说的那样,我的建议不要试图将指针指向一个临时变量,从不这样做。没有犯罪,请更正您的代码。