在C语言中删除特定字符后的字符串结尾

3

我尝试在C语言中根据某个特定字符结束字符串。由于该程序将与文件系统一起使用,因此该字符将被重复使用,我需要找到该字符的最后一个出现并删除其后的所有内容。

我在互联网上找到了一些东西,但它不起作用,我不知道为什么。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void deleteEnd (char* myStr){

    printf ("%s\n", myStr);
    char *del = &myStr[strlen(myStr)];

    while (del > myStr && *del != '/')
        del--;

    if (*del== '/')
        *del= '\0'; // the program crashes here

    return;
}

int main ( void )
{

    char* foo= "/one/two/three/two";
    deleteEnd(foo);
    printf ("%s\n", foo);

    return 0;
}

这段代码基本上是查找最后一个 '/' 字符并将空终止符放在那里。理论上它是可行的,但实际上却不是。
顺便说一下,如果我的方法是错误的,有更好的方法吗?
谢谢。
**编辑:根据建议,我用 "strrchr()" 替换了我的代码,但仍然没有结果:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void deleteEnd (char* myStr){

    char *lastslash;

    if (lastslash = strrchr(myStr, '/'))
        *lastslash = '\0'; // the code still crashes here.

    return;
}

int main ( void )
{

    char* foo= "/one/two/three/two";
    deleteEnd(foo);
    printf ("%s\n", foo);

    return 0;
}

3
char *lastslash; if (lastslash = strrchr(myStr, '/')) *lastslash = '\0'; - EOF
2
你的代码试图修改 foo 指向的常量字符串。首先尝试将其复制到 char 数组中,然后从 strlen(mystr)-1 开始分配 'del',这是实际包含在字符串中的最后一个字节。无论如何,像这样进行指针算术并不是一个好主意,因此最好从结尾到开头使用查找,可以使用循环或 strrchr()。 - DNT
1
@DNT:我认为你对于 strlen()-1 是错误的。考虑一个空字符串:strlen("") 的结果是零,你肯定不想引用 strlen("")-1 - EOF
@EOF 在任何其他操作之前,应该先检查这个空字符串条件,并且代码应该直接返回而不尝试更改任何内容。同样的情况也适用于没有找到'/'的情况。然而,当s为"abcde"时,strlen(s)的值为5,但数组中的索引将从0到4。索引5是一个字节之外。 - DNT
@EOF 你能举个例子说明当str为"abcde"时,str[strlen(str)]引用的是哪个有效元素吗?如果你指的是零终止符,那么好吧,但这并不是在搜索斜杠字符。 - DNT
显示剩余4条评论
6个回答

4
在C语言中,如果你像这样写字符串字面量: char* foo= "/one/two/three/two"; 那么这些字符串是不可变的,也就是说它们被嵌入到可执行文件中并且是只读的。 当你试图修改只读数据时,会导致访问冲突(崩溃)。 相反,你可以将字符串声明为字符数组,而不是字符串字面量。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void deleteEnd (char* myStr){

    printf ("%s\n", myStr);
    char *del = &myStr[strlen(myStr)];

    while (del > myStr && *del != '/')
        del--;

    if (*del== '/')
        *del= '\0';

    return;
}

int main ( void )
{

    char foo[] = "/one/two/three/two";
    deleteEnd(foo);
    printf ("%s\n", foo);

    return 0;
}

如果这段代码重复了,会不会占用太多空间?我计划将这个片段放入递归函数中,所以我想会。有没有降低所需内存的方法? - cskr
将字符串声明为数组而不是字面字符串。 - Felipe Romero

1

是的char *lastslash;

if (lastslash = strrchr(myStr, '/'))
    *lastslash = '\0'; // the code still crashes here.

return;

}

int main ( void ) {

char foo[]= "/one/two/three/two";
deleteEnd(foo);
printf ("%s\n", foo);

0
只需将foo声明为一个字符数组,而不是指向字符的指针即可:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void deleteEnd (char* myStr){

    char *lastslash;

    if (lastslash = strrchr(myStr, '/'))
        *lastslash = '\0'; // the code still crashes here.

    return;
}

int main ( void )
{

    char foo[]= "/one/two/three/two";
    deleteEnd(foo);
    printf ("%s\n", foo);

    return 0;
}

如果我这样做,我还能使用realloc()、strdup()或strcat()等函数吗? - cskr
realloc() 只能用于由 malloc()realloc() 自身分配的内存,而 foo 的内存不是以这种方式分配的。只要不超过数组的最大大小,strcat() 就可以工作。也就是说,在初始化时分配给数组的字节数。strdup() 可以毫无问题地与字符串 foo 一起使用。 - mcleod_ideafix
感谢您的解释 :) - cskr

0

你不能在字符串常量中进行更改,必须复制到一个新的 char 字符串。

#include <iostream>
#include <cstring>

void delete_end(char* dest, const char* source)
{
    const char* p = source + strlen(source) - 1;
    while(*p != '/' && p > source)
        --p;
    strncpy(dest, source, p - source);
    dest[p-source] = '\0';
}

int main()
{

    const char* str = "one/two/three/four";
    char buf[256];
    delete_end(buf, str);
    std::cout << buf << std::endl;

    return 0;
}

这太过复杂了。你可以一开始就获取一个副本…… char str[] = "one/two/three/four"; 不需要使用 strncpy 或者多余的缓冲区等等。 - Lightness Races in Orbit

0
  1. 从第一个字符开始。
  2. 扫描当前字符,它是 / 吗?不是?转到步骤 3。是的?转到步骤 4。
  3. 还有另一个字符吗?没有?转到步骤 5。是的?继续下一个字符并转到步骤 2。
  4. 将 "lastSlash" 变量设置为当前字符位置。转到步骤 2。
  5. 删除 lastSlash 位置之后的所有内容。完成!

我想我正在尝试你在这里说的事情。我是从后往前查找字符,试图删除其余部分,但失败了。老实说,你说的并没有帮助。 - cskr
我猜你实际上不会C语言?我现在没有时间为你打字,但如果其他答案都没有的话,我稍后会做的。 - GAdr
我想你实际上并没有读我的问题?我不需要任何跟进,我已经得到了答案。无论如何,还是谢谢。 - cskr

0

在C语言中查找字符串中某个字符的最后一次出现,可以使用strrchr(3)函数。它的原型在<string.h>头文件中声明。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接