【问题标题】:Assertion Failure on function using ispunct使用 ispunct 函数断言失败
【发布时间】:2026-02-15 17:20:03
【问题描述】:

在构建“ReplacePuncsWithBlanks”函数后,我遇到了断言失败。这与我在数组的开头和结尾插入空格有什么关系吗?

 #include <iostream>
    #include <ctype.h>

    using namespace std;

    const int SIZE = 100;

    void GetString(char StringArray[]);
    void CopyString(char StringArray[], char CopiedArray[]);
    void MakeUpper(char CopiedArray[]);
    void InsertBlanks(char CopiedArray[]);
    void ReplacePuncsWithBlanks(char CopiedArray[]);
    void DisplayString(char StringArray[], char CopiedArray[]);   

    int main()
    {
        char StringEntered[SIZE];
        char CopiedString[SIZE];

        GetString(StringEntered);
        CopyString(StringEntered, CopiedString);
        MakeUpper(CopiedString);
        InsertBlanks(CopiedString);
        ReplacePuncsWithBlanks(CopiedString);
        DisplayString(StringEntered, CopiedString);

    cout<<"Hit Enter.\n";
    cin.ignore();

    }
/***************************************GetString********************************************
*   Action:         Prompts user to enter some text.                                        *
*                                                                                           *
*   Parameters:                                                                             *
*       IN:                                                                                 *
*                                                                                           *
*       OUT:        StringArray which is the array holding the original text inputted by    *
*                   the user                                                                *
*                                                                                           *
*   Returns:        Nothing.                                                                *
*                                                                                           *
*   Precondition:   StringArray points to StringEntered array in Main.                      *
*********************************************************************************************/
void GetString(char StringArray[])
{
    cout<<"Please enter a sentence:  ";
    cin.getline(StringArray, SIZE);
}


/***************************************CopyString********************************************
*   Action:         Copies data from one array (StringArray) to another (CopiedArray).      *
*                                                                                           *
*   Parameters:                                                                             *
*       IN:         StringArray which has existing data.                                    *
*                                                                                           *
*       OUT:        CopiedArray which will be a copy of StringArray.                        *
*                                                                                           *
*   Returns:        Nothing.                                                                *
*                                                                                           *
*   Precondition:   StringArray points to StringEntered array in Main.                      *
*                   CopiedArray points to CopiedString array in Main.                       *
*********************************************************************************************/
void CopyString(char StringArray[], char CopiedArray[])
{
    for(int i=0; i<SIZE; ++i)
    {
        CopiedArray[i]=StringArray[i];
    }
}


/**************************************MakeUpper*********************************************
*   Action:         Changes characters in the array to an uppercase letter.                 *
*                                                                                           *
*   Parameters:                                                                             *
*       IN:         CopiedArray which has mixed case letters.                               *
*                                                                                           *
*       OUT:        CopiedArray which will have uppercase letters.                          *
*                                                                                           *
*   Returns:        Nothing.                                                                *
*                                                                                           *
*   Precondition:   CopiedArray points to CopiedString array in Main.                       *
*********************************************************************************************/
void MakeUpper(char CopiedArray[])
{
    char c;
    for(int i=0; i<SIZE; ++i)
    {
        c=CopiedArray[i];
        CopiedArray[i]=toupper(c);
    }
}


/***********************************InsertBlanks*********************************************
*   Action:         Moves elements in the array up one spot and replaces the first element  *
*                   with a space as well as the last element.
*                                                                                           *
*   Parameters:                                                                             *
*       IN:         CopiedArray prior to inserting the spaces.                              *
*                                                                                           *
*       OUT:        CopiedArray which will have a space in the first element and at the end.*
*                                                                                           *
*   Returns:        Nothing.                                                                *
*                                                                                           *
*   Precondition:   CopiedArray points to CopiedString array in Main.                       *
*********************************************************************************************/
void InsertBlanks(char CopiedArray[]){
    int temp=0;
    for (int i=SIZE-1; i>0; --i)
    {
        if(CopiedArray[i]=='\0')
        {
            temp=i+1;
        }
        CopiedArray[i]=CopiedArray[i-1];
    }
    CopiedArray[0]=' ';
    CopiedArray[temp]=' ';
    CopiedArray[temp+1]='\0';
}

/********************************ReplacePuncsWithBlanks**************************************
*   Action:         Changes characters which are punctuation to whitepaces.                 *
*                                                                                           *
*   Parameters:                                                                             *
*       IN:         CopiedArray which may include punctuation.                              *
*                                                                                           *
*       OUT:        CopiedArray which will have have replaced punctuations with whitespaces.*
*                                                                                           *
*   Returns:        Nothing.                                                                *
*                                                                                           *
*   Precondition:   CopiedArray points to CopiedString array in Main.                       *
*********************************************************************************************/
void ReplacePuncsWithBlanks(char CopiedArray[])
{
    for (int i=0; i<SIZE; ++i)
    {
        if (ispunct(CopiedArray[i]))
        {
            cout<<CopiedArray[i];
        }
    }

}

void DisplayString(char StringArray[], char CopiedArray[])
{
    for(int i=0; i<SIZE; ++i)
    {
        if(StringArray[i]!='\0')
        {
            cout<<StringArray[i];
        }
        else
        {
            i=(SIZE-1);
        }
    }
    cout<<endl;

    for(int x=0; x<SIZE; ++x)
    {
        if(CopiedArray[x]!='\0')
        {
            cout<<CopiedArray[x];
        }
        else
        {
            x=(SIZE-1);
        }
    }
    cout<<endl;
}

有什么想法吗?

【问题讨论】:

  • 你能显示分配和填充CopiedArray的代码吗? SIZE 的定义也很重要。
  • 添加了其余的代码。谢谢你的关注。
  • 代码对我有用。您提供了什么输入以使其失败?
  • 首先,我使用的是非常简单的文本,(你好,等等)这可能是我的 Visual Studio 的问题吗?

标签: c++ arrays function visual-studio-2012 ctype


【解决方案1】:

main 函数的开头,StringEnteredCopiedString 都包含垃圾。

GetString 函数从输入中读取一行并将StringEntered开头 替换为您输入的内容。然后是\0 字节,剩下的垃圾仍然存在。

稍后,CopyString 将您的输入、\0 字节和垃圾复制到CopiedString

然后,函数ReplacePuncsWithBlanks 对该内存块的每个字节进行操作。对于你调用ispunct的每个字节,这个函数很特别。它并不期望它的参数是char 类型(你可能认为),而是unsigned char 类型。有关详细信息,请参阅documentation

问题是char 在您的平台上可以有一个介于 -128 和 127 之间的值,并且字符串末尾的垃圾肯定包含一些负值。这些值不允许作为 ispunct 函数的参数。

您很幸运遇到了断言错误。您的程序也可能默默地失败或使您的计算机爆炸。这称为未定义的行为

要解决此问题,您需要将参数转换为正确的类型:

void ReplacePuncsWithBlanks(char CopiedArray[])
{
    for (int i=0; i<SIZE; ++i)
    {
        if (ispunct((unsigned char)CopiedArray[i]))
        {
            cout<<CopiedArray[i];
        }
    }
}

最好是在看到字符串结尾字节后立即停止循环:

for (int i = 0; i < SIZE && CopiedArray[i] != '\0'; i++) {

但即使那样你也需要类型转换。

【讨论】: