使用指针和修剪前导空格重现字符数组

时间:2013-11-14 13:26:40

标签: c++ arrays pointers

我正在自己学习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;
}

3 个答案:

答案 0 :(得分:3)

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

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

这仍然只会给您"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参数,因此可以将其删除。

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

答案 2 :(得分:-1)

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

*ptrMsg=msg // or ptrMsg=&msg 

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

关于为什么GREAT&amp;不是伟大的,那是因为msg&amp; ptrMsg具有非常不同的地址,即你不用ptrMsg重写msg。在定义ptrMsg时,你将msg的内容复制到ptrMsg,&amp;未分配地址....

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