c ++动态分配char *

时间:2017-04-26 00:43:44

标签: c++ dynamic-allocation

我在下面的代码中遇到问题,问题只是动态分配的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

我期待上部和下部是相同的,不一样的意思是即使我做了一些错误并且没有注意到或者我不知道使用动态的东西分配

4 个答案:

答案 0 :(得分:2)

返回的指针指向的数组std::string::c_strstring所有。 substr返回一个临时string对象,该对象在调用substr的表达式末尾超出范围。

将这两个事实结合在一起意味着argv中指针指向的数组在创建后立即被删除。当你开始打印它们时,它们已经很久了。

答案 1 :(得分: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

当在{}作用域中运行时,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有些奇怪。但我不确定。我会继续检查。 并且,如上面的代码所示,p和p1指向不同的临时变量,根据不同的输出,p和p1可能指向第一个示例中的相同临时变量。 让我们回到你的代码,char **是指针的指针,经常使指针指向临时变量是错误的。 我的建议是你可以使用string数组而不是指针数组。 希望有所帮助。

答案 2 :(得分:0)

您没有为创建的临时子字符串字符串对象分配任何内容,这会创建一个指向数组的临时指针。

做这样的事情应该有效但不会推荐,因为你不能再释放那个记忆了:

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

当c_str返回一个指向字符串对象值的常量指针时,您需要生存字符串对象。如果字符串对象不存在,那么指针指向什么?阅读:c_str cplusplus.com

建议将子字符串存储到某个数组/向量中,然后使用指针进行必要的工作。

答案 3 :(得分:0)

@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

但正如我们所知,当我们最后一次尝试打印'b'时,'c''a'已经消失。为什么&#39; a&#39;仍然有价值?

原因是'b''c'的内存和数据仍然存在,尽管'b''c'已经消失。 &#39;一个&#39;是一个参考,它指的是'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;
}

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