5

我正在自己学习 C++ 并正在解决这个问题:

编写一个名为 trimfrnt() 的函数,从字符串中删除所有前导空格。使用返回类型为 void 的指针编写函数。

我对这个问题的尝试如下,我尝试以两种方式解决这个问题(你可以看到我的两个函数trimfrnt1()trimfrnt2(). trimfrnt1()工作正常。我有点意外地得到了这个工作。在我编码之后,我不确定它为什么会这样工作。我的困惑在于for循环。我在下面画了一个 msg 数组的图表:

             |<--ptrMsg--------->|
  |<------for loop---->|
   0    1    2   3     4   5     6    7
+----+----+----+----+----+----+----+----+
|    |    |  G |  R |  E |  A |  T | \0 |
+----+----+----+----+----+----+----+----+
|  G |  R |  E |  A |  T |    |    | \0 |                             
+----+----+----+----+----+----+----+----+                                

问题 1

从上图中,由于重叠,我实际上期待文本:“GREATAT”。因为我只循环了 5 个字母,所以整个字符串如何移动并重新初始化?

问题2

问题说明要使用指针,所以我虽然trimfrnt1在作弊,因为我正在编制索引,所以我尝试使用另一种trimfrnt2. 这个函数我被困在while循环中:

    // shift characters to beginning of char array
    while( *(ptrMsg + count) != '\0' )
    {        
        *ptrMsg = *(ptrMsg + count);
        ptrMsg++;
        count++;
    }

这部分代码对我不起作用。当我打印出来时*(ptrMsg + count),我得到了正确的字符,但是当我将它分配给 *ptrMsg 的内容时,我得到了乱码。在这种情况下,我也期待“GREATAT”,因为我没有重新初始化剩余的字符。有没有办法像我试图做的那样使用指针方法来做到这一点?

谢谢!

#include<iostream>
#include<iomanip>

using namespace std;

void trimfrnt1(char msg[], int size)
{
    char *ptrMsg = msg;

    // Find beginning of text
    while(*ptrMsg == ' ')
        ptrMsg++;

    // Copy text to beginning of array
    for(int i=0; i < size; i++)
        msg[i] = *ptrMsg++;

    // Reset pointer to beginning of array
    ptrMsg = msg;

    // Print array
    cout << "new msg1: ";
    cout << "\"" << ptrMsg << "\"" << endl;    
    cout << endl;

    return;
}

void trimfrnt2(char msg[], int size)
{
    int count = 0;      // used to find leading non-white space
    char *ptrMsg = msg; // pointer to character array

    // find first place of non white space
    while( *(ptrMsg + count) == ' ')
        count++;

    cout << "count = " << count << endl;

    // shift characters to beginning of char array
    while( *(ptrMsg + count) != '\0' )
    {        
        *ptrMsg = *(ptrMsg + count);
        ptrMsg++;
        count++;
    }
    cout << "count = " << count << endl;

    // Reset pointer to beginning of array
    ptrMsg = msg;

    // Print array
    cout << "new msg2: ";
    cout << "\"" << ptrMsg << "\"" << endl;    
    cout << endl;
}


int main()
{
    char msg[] = "  GREAT";
    const int size = sizeof(msg)/sizeof(char);

    cout << "Orginal msg:\"" << msg << "\"" << endl;

    trimfrnt1(msg, size);

    return 0;
}
4

3 回答 3

3

trimfrnt1()具有未定义的行为 - 您for循环导致ptrMsg超出数组,因此您正在读取不属于您的内存并且任何事情都可能发生。似乎在您的平台上,这样的读取是可以的,所以循环很乐意从内存中复制“随机”垃圾 - 但在此之前,它会复制终止NUL字符,因此您无法获得"GREATAT"结果。您应该像这样更改while循环:

while(*ptrMsg == ' ')
{
  ptrMsg++;
  --size;
}

这仍然会给你 just "GREAT",因为终止NULsizeof结果的一部分。

trimfrnt2()中,您的循环是错误的,因为您正在增加count,这是您不应该的。这就是为什么给变量提供真正描述性的名称是很好的。如果在其语义(例如numberOfSpaces)之后调用它,您甚至不会考虑在复制while()循环中编写增量。如果您删除该增量,trimfrnt2()应该会给"GREATAT"您预期的结果。


为了获得灵感,以下是我将如何使用不带算术的指针来实现它:

void trimfrnt3(char *msg, size_t size)
{
  const char *src = msg;
  while (*src == ' ')
    ++src;
  char *dst = msg;
  while (*src)
  {
    *dst = *src;
    ++src;
    ++dst;
  }
  cout << "new msg: \"" << msg << "\"\n";  //don't use endl unless you want to flush immediately
}

如您所见,此版本甚至不使用该size参数,因此可以将其删除。

于 2013-11-14T13:36:54.050 回答
1

里面的问题trimfrnt2

*ptrMsg = *(ptrMsg + count);
ptrMsg++;
count++;

它将ptrMsg向源和目标推进。你应该删除count++. 循环后,您应该\0输入结果。

while( *(ptrMsg + count) != '\0' )
{
    *ptrMsg = *(ptrMsg + count);
    ptrMsg++;
    //count++;
}
*ptrMsg = '\0';

它可以帮助你

void trim_left(char *msg)
{
    char *src = msg;
    char *dst = msg;

    while (*src == ' ')
        src++;

    if (dst == src)
        return; // Don't need trim

    while (*src)
        *dst++ = *src++;

    *dst = 0;
}
于 2013-11-14T13:40:14.413 回答
-1

关于垃圾值,这是因为在第二个 while 循环之后,您使用 Msg(char) 分配了一个 ptrMsg(char 指针)。它应该是

*ptrMsg=msg // or ptrMsg=&msg 

此外,您在 cout 中打印 ptrMsg,它打印的是地址,而不是值。

关于为什么 GREAT & not GREATAT,那是因为 msg 和 ptrMsg 有非常不同的地址,即您没有用 ptrMsg 重写 msg。在定义 ptrMsg 时,您将 msg 的内容复制到 ptrMsg,并且没有分配地址....

ptrMsg=&msg  // ptrMsg contains address of string msg
*ptrMsg=msg  // address pointed by ptrMsg has same content as msg,but both have different address altogether 
于 2013-11-14T13:51:22.000 回答