使用ispunct的函数断言失败

Assertion Failure on function using ispunct

本文关键字:断言 失败 函数 ispunct 使用      更新时间:2023-10-16

在构建"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]=='')
{
temp=i+1;
}
CopiedArray[i]=CopiedArray[i-1];
}
CopiedArray[0]=' ';
CopiedArray[temp]=' ';
CopiedArray[temp+1]='';
}
/********************************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]!='')
{
cout<<StringArray[i];
}
else
{
i=(SIZE-1);
}
}
cout<<endl;
for(int x=0; x<SIZE; ++x)
{
if(CopiedArray[x]!='')
{
cout<<CopiedArray[x];
}
else
{
x=(SIZE-1);
}
}
cout<<endl;
}

有什么想法吗?

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

GetString函数从输入中读取一行,并将StringEntered开头替换为您输入的内容。然后跟随一个字节,剩余的垃圾将保留下来。

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

然后,函数ReplacePuncsWithBlanks对该存储器块的每个字节进行操作。对于每个字节,您调用ispunct,这个函数非常特殊。它不希望它的参数是char类型(您可能认为是这样),而是unsigned char类型。有关更多详细信息,请参阅文档。

问题是,在您的平台上,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] != ''; i++) {

但即便如此,你也需要类型转换。