c++ - 识别字符串格式调试断言
问题描述
下面的代码存在运行时问题。
目的是“识别”输入字符串中的格式(%s %d 等)。
为此,它返回一个与数据类型匹配的整数。然后提取的类型在其他函数中进行操作/处理。
我想澄清一下,我的目的不是在字符串(snprintf 等)中编写格式化类型,而只是识别/提取它们。
问题是我的应用程序崩溃并出现错误:
Debug Assertion Failed!
Program:
...ers\Alex\source\repos\TestProgram\Debug\test.exe
File: minkernel\crts\ucrt\appcrt\convert\isctype.cpp
Line: 36
Expression: c >= -1 && c <= 255
我的代码:
#include <iostream>
#include <cstring>
enum Formats
{
TYPE_INT,
TYPE_FLOAT,
TYPE_STRING,
TYPE_NUM
};
typedef struct Format
{
Formats Type;
char Name[5 + 1];
} SFormat;
SFormat FormatsInfo[TYPE_NUM] =
{
{TYPE_INT, "d"},
{TYPE_FLOAT, "f"},
{TYPE_STRING, "s"},
};
int GetFormatType(const char* formatName)
{
for (const auto& format : FormatsInfo)
{
if (strcmp(format.Name, formatName) == 0)
return format.Type;
}
return -1;
}
bool isValidFormat(const char* formatName)
{
for (const auto& format : FormatsInfo)
{
if (strcmp(format.Name, formatName) == 0)
return true;
}
return false;
}
bool isFindFormat(const char* strBufFormat, size_t stringSize, int& typeFormat)
{
bool foundFormat = false;
std::string stringFormat = "";
for (size_t pos = 0; pos < stringSize; pos++)
{
if (!isalpha(strBufFormat[pos]))
continue;
if (!isdigit(strBufFormat[pos]))
{
stringFormat += strBufFormat[pos];
if (isValidFormat(stringFormat.c_str()))
{
typeFormat = GetFormatType(stringFormat.c_str());
foundFormat = true;
}
}
}
return foundFormat;
}
int main()
{
std::string testString = "some test string with %d arguments"; // crash application
// std::string testString = "%d some test string with arguments"; // not crash application
size_t stringSize = testString.size();
char buf[1024 + 1];
memcpy(buf, testString.c_str(), stringSize);
buf[stringSize] = '\0';
for (size_t pos = 0; pos < stringSize; pos++)
{
if (buf[pos] == '%')
{
if (buf[pos + 1] == '%')
{
pos++;
continue;
}
else
{
char bufFormat[1024 + 1];
memcpy(bufFormat, buf + pos, stringSize);
bufFormat[stringSize] = '\0';
int typeFormat;
if (isFindFormat(bufFormat, stringSize, typeFormat))
{
std::cout << "type = " << typeFormat << "\n";
// ...
}
}
}
}
}
正如我在代码中评论的那样,使用第一个字符串一切正常。而第二个,应用程序崩溃。
我还想问您是否有更好/更高效的方法来识别字符串中的类型“%d %s etc”?(甚至不一定返回一个 int 来识别它)。
谢谢。
解决方案
我们来看看这个else
条款:
char bufFormat[1024 + 1];
memcpy(bufFormat, buf + pos, stringSize);
bufFormat[stringSize] = '\0';
该变量stringSize
使用原始格式字符串的大小进行初始化。假设在这种情况下它是 30。
假设您%d
在偏移量 20 处找到代码。您将从偏移量 20 开始的 30 个字符复制到bufFormat
. 这意味着您要复制原始字符串末尾的 20 个字符。您可以阅读原文的结尾buf
,但这里不会发生这种情况,因为buf
它很大。第三行将 NUL 设置到缓冲区的第 30 位,再次超过数据的末尾,但是您memcpy
将 NUL 从复制到buf
into bufFormat
,所以这就是字符串 in 的bufFormat
结束位置。
现在bufFormat
包含字符串“%d 个参数”。在里面isFindFormat
搜索第一个isalpha
字符。可能你是说isalnum
这里?因为只有通过检查才能到达isdigit
线路,如果是,则不是。isalpha
isalpha
isdigit
无论如何,isalpha
通过后,isdigit
肯定会返回false
,因此我们进入该if
块。您的代码将在此处找到正确的类型。但是,循环不会终止。相反,它继续扫描最多stringSize
字符,即stringSize
from main
,即原始格式字符串的大小。但是您传递给的字符串isFindFormat
仅包含以“%”开头的部分。因此,您将扫描字符串的末尾并读取缓冲区中的任何内容,这可能会触发您看到的断言错误。
这里还有很多事情要做。您正在混合和匹配std::string
C 字符串;看看你是否可以使用std::string::substr
而不是复制。您可以使用std::string::find
在字符串中查找字符。如果必须使用 C 字符串,请使用strcpy
而不是memcpy
后跟 NUL。
推荐阅读
- javascript - 遍历具有不同值的数组
- python - 检查类型提示是否已注释的正确方法是什么?
- java - sqlMapClientTemplate:空数组参数导致 BadSqlGrammarException
- flutter - 在flutter中从json文件中获取数据时,类型'String'不是'index'类型'int'的子类型
- docker - 使用 IIS 托管 Docker 容器
- ios - Angular SPA PWA - Safari iOS 选项卡图标不会改变
- python - raise KeyError(key) from err: 尝试从 finnhub API 检索财务数据
- c# - LINQ - 如果给定 ID 包含 xyz,则返回所有行
- python - 尝试使用 pandas 数据框中其他两列的 groupby 基于另一列创建新的滚动平均列时出错
- kotlin - 如何从 Firebase 获取符合两个条件的数据,其中一个条件是数组?