我使用以下内容从变量中删除空格
for (i=0, ptr=lpsz;ptr[i];ptr++)
{
if (*ptr == ' ')
i++;
*ptr = ptr[i];
}
*ptr=0;
但是,当有多个空间时,它似乎有问题,我不确定我做错了什么。任何人都可以帮助我吗?
我使用以下内容从变量中删除空格
for (i=0, ptr=lpsz;ptr[i];ptr++)
{
if (*ptr == ' ')
i++;
*ptr = ptr[i];
}
*ptr=0;
但是,当有多个空间时,它似乎有问题,我不确定我做错了什么。任何人都可以帮助我吗?
我建议你使用std::isspace
而不是做你的指针魔术。
如果您将 a与您std::string
结合使用,则可以执行以下操作:std::isspace
std::string str = "Hello World Today";
str.erase(remove_if(str.begin(), str.end(), isspace), str.end());
字符串实际上只是一个字符容器,因此您可以对其应用擦除/删除习语。
这应该有效。考虑两个指针在字符串中移动比考虑一个指针加上一个偏移量要容易得多。
auto sptr = lpsz;
auto dptr = lpsz;
while (*dptr = *sptr) { // copy up to and including terminating NUL
if (*dptr != ' ') dptr++; // but spaces take no slots in the destination
sptr++;
}
甚至
auto sptr = lpsz;
auto dptr = lpsz;
while (auto c = *dptr = *sptr) {
dptr += (c != ' ');
sptr++;
}
这段代码与原始代码的本质区别在于,当我们看到除空格以外的其他内容时,我的和原始代码都将读写位置向前移动一个。但是当我们看到一个空格时,我将读取位置向前移动 1 并且不移动写入位置,而原来的将读取位置向前移动 2 并且将写入位置向前移动 1,这会跳过一个字符。此外,原件是在写入位置测试空格,而不是在读取位置(我的测试写入位置,但它是在从读取位置复制字符后进行的,所以结果是正确的)。
您应该为此使用算法,因为它们经过了很好的测试。但是,如果您想分析您的代码并了解故障,请考虑对您的代码正在运行的内容进行高级描述(参见 Tony 的回答)。
您在缓冲区中维护两个索引,一个用于读取,一个用于写入。每当读取头检测到一个空格时,您就会移动它但跳过写入。如果字符不是空格,则使用读取头获取值并通过写入头写入。
在您的实现中,读头是ptr+i
,作为写头的偏移量,它的拼写有点奇怪(如ptr[i]
)。写头是ptr
( *ptr =
)。但是您在循环中的测试使用的是写头而不是读头:if (*ptr==' ')
。
即使你解决了这个问题,实现也会有其他问题,例如,如果有两个连续的空格,因为你在循环中做了一个测试。您的算法的重写可能是:
char* remove_spaces(char* buffer) {
char *read = buffer;
for (char *read = buffer; (*read), ++read) {
if (*read != ' ') { // copy element
*buffer = *read;
++buffer; // and increment write head
}
}
*buffer = 0; // ensure null termination
return read;
}
现在,如果您对第一个空间进行初始搜索并将其用作上述循环的起点,则可以通过删除对内存的写入次数来进一步改进算法(性能)。这将减少操作的数量和标记为脏的缓存行的数量。
仔细地遍历你的循环。
i
在循环开始时设置为 0。对于遇到的第一个空格,i
递增 (so i==1
)。at 的字符ptr
被替换为 at 的字符prt+i
,即下一个字符。这是第一次工作,因为i
是 1。
但是对于第二个空格,i
设置为 2(因为它是递增的),所以空格被替换为字符ptr+2
作为字符串副本的一部分而不是就地更改,这样做会容易得多。
dest
是我们更改副本的目标缓冲区。
for(ptr = lpsz; *ptr; ptr++){
if(' ' == *ptr) {continue;}
*dest = *ptr;
dest++;
}
*dest = 0;