【问题标题】:Remove specified char from strings in C从 C 中的字符串中删除指定的字符
【发布时间】:2015-06-02 23:48:54
【问题描述】:

我正在制作一个程序,它将在字符串数组中搜索,并且对于每个字符串,它将搜索指定的字符。如果找到该字符,请将其删除。在本例中,我想删除字符 'r'。

代码如下:

void convertStrings(char **line) {
    for (int str = 0; str < MAX_LINE_LENGTH; ++str) {
        for (int ch = 0; ch < MAX_STR_LENGTH; ++ch) {
            if (line[str][ch] == 'r') {
                removeChar(line[str], 'r');
            }
        }
    }
}

void removeChar(char *str, char c) {
    int i = 0;
    int j = 0;

    while (str[i]) {
        if (str[i] != c) {
            str[j++] = str[i];
        }
        i++;
    }
    str[j]=0;
}

我不确定删除字符的算法是否正确,但主要错误在其他地方。更具体地说,我在该行中遇到了分段错误:

if (line[str][ch] == 'r') {

为什么会出现段错误?另外,removeChar 的算法是否正确?

这是我的主要功能:

int main() {
    char line[3][10] = {"pep", "rol", "rak"};
    printf("%s\n", line[1]);
    convertStrings(line);
    printf("%s\n", line[1]);
    return 0;
}

提前致谢。

【问题讨论】:

  • "为什么会出现段错误?" -- 不知道。我们将不得不查看更多代码(具体来说,您如何调用convertStrings 以及MAX_LINE_LENGTHMAX_STR_LENGTH 的值是什么)。 "另外,removeChar 的算法是否正确?" -- 是的。好像是这样。
  • 您确定line 包含准确的MAX_LINE_LENGTH 行,并且每个字符串准确包含MAX_STR_LENGTH 字符吗?
  • 你是否为双指针line指向的对象分配了足够的内存?
  • 我在问题中添加了我的主要功能。
  • @pk163 , MAX_LINE_LENGTHMAX_STR_LENGTH 的值是多少?

标签: c string char


【解决方案1】:

此代码适用于我的编译器:

#include<stdio.h>
#include<conio.h>
#define MAX_LINE_LENGTH 1024
#define MAX_STR_LENGTH 4
void removeChar(char *str, char c) {
int i = 0;
int j = 0;

while (str[i]) {
    if (str[i] != c) {
        str[j++] = str[i];
      }
    i++;
}
str[j]=0;
}

void convertStrings(char line[][MAX_STR_LENGTH]) {    //change 1
 for (int str = 0; str < MAX_LINE_LENGTH; ++str) {
    for (int ch = 0; ch < MAX_STR_LENGTH; ++ch) {
        if (line[str][ch] == 'r') {
removeChar(line[str], 'r');
        }
    }
  }
}


int main() {
 char line[3][MAX_STR_LENGTH] = {"pep", "rol", "rak"};   //change 2
 printf("%s\n", line[1]);
 convertStrings(line);
 printf("%s\n", line[1]);
 getch();
 return 0;
}

【讨论】:

    【解决方案2】:

    这是因为line[str][ch] 不存在您为str 和/或ch 提供的所有值。

    您应该检查MAX_LINE_LENGTHMAX_STR_LENGTH 的值并确保它们是正确的。

    【讨论】:

      【解决方案3】:

      段错误可能是因为您使用了常量“MAX_LINE_LENGTH”和“MAX_STR_LENGTH”,但是可能有行长或字符串长度。我会在第一个 for 循环中使用数组的长度作为变量 str 而不是“MAX_LINE_LENGTH”,并使用数组 [str] 的长度而不是“MAX_STR_LENGTH”。除非您正在搜索的每个数组都有“MAX_LINE_LENGTH”并且每个字符串都有“MAX_LINE_LENGTH”,否则您将得到一个设置错误。希望这会有所帮助!

      编辑:你可以通过除以数组的大小和元素类型的大小来找到数组的长度。

      sizeof(array)/sizeof(array[0])
      

      查找char指针大小的过程基本相同。

      【讨论】:

      • 是的,但如果不是数组中的每个元素都具有相同的大小怎么办?
      【解决方案4】:

      因为数组line 包含少于MAX_LINE_LENGTH 字符串指针,或者因为至少有一个指向的字符串包含少于MAX_STR_LENGTH 字符,您会遇到段错误;更可能是后者。

      与其假设固定数量的固定长度的字符串,不如将实际个字符串作为参数传递。或者,您可以在列表末尾添加 NULL 作为标记值。

      此外,没有任何理由假设每个字符串都是固定长度的。寻找终止字符 ('\0') 以识别您何时到达终点。例如:

      void convertStrings(char **line) {
          for (char **l = line; *l != NULL; l += 1) {
              for (int ch = 0; (*l)[ch]; ch += 1) {
                  if ((*l)[ch] == 'r') {
                      removeChar(*l, 'r');
                  }
              }
          }
      }
      

      你的removeChar() 函数看起来没问题。

      但是请注意,有一些库函数可以帮助解决这个问题(例如strchr()),并且可能有各种效率改进(例如仅将字符串尾部传递给removeChar(),从第一个开始要删除的角色的外观)。

      【讨论】:

        【解决方案5】:

        你有数组

        char line[3][10] = {"pep", "rol", "rak"};
        

        当你将它传递给一个函数时,它会被转换为一个char(*)[10] 类型的指针。所以改变

        void convertStrings(char **line) {
        

        void convertStrings(char (*line)[10]) {
        

        void convertStrings(char line[][10]) {
        

        数组数组(二维数组)不能转换为指向指针的指针(本例中为char**


        另一个问题是 you mention that MAX_LINE_LENGTH 是 1024 而 MAX_STR_LENGTH 是 4。这是错误的,因为循环会迭代并且您访问无效的内存位置。您应该将 MAX_LINE_LENGTH 设为 3,将 MAX_STR_LENGTH 设为 4,因为有 3 个字符串,每个字符串有 4 个字符。
        您也可以将这些变量作为参数传递给函数convertStrings。在convertStrings的声明中更改添加两个参数:

        void convertStrings(char (*line)[10], int MAX_LINE_LENGTH, int MAX_STR_LENGTH) {
        

        void convertStrings(char line[][10], int MAX_LINE_LENGTH, int MAX_STR_LENGTH) {
        

        并使用

        main 调用函数
        convertStrings(line, sizeof(line)/sizeof(*line), sizeof(*line)/sizeof(**line)); // `/sizeof(**line)` is 1 and is not needed
        


        更好的方法是使用
        void convertStrings(int MAX_LINE_LENGTH, int MAX_STR_LENGTH, char line[][MAX_STR_LENGTH]) {
        

        void convertStrings(int MAX_LINE_LENGTH, int MAX_STR_LENGTH, char (*line)[MAX_STR_LENGTH]) {
        

        然后调用函数

        convertStrings(sizeof(line)/sizeof(*line), sizeof(*line)/sizeof(**line), line); // `/sizeof(**line)` is 1 and is not needed
        

        这样您就可以避免在函数中使用幻数 10。


        你肯定会从你的编译器那里得到一些警告。注意他们。如果您没有收到警告,请在编译器中启动警告并包含警告标志(如 GCC 中的 -Wall )。

        顺便说一句,您可以查看string.h 中的strchr 函数以查找字符串中是否存在字符。

        【讨论】:

        • 你对二维数组相对于双指针是正确的,这当然可以解释这个问题。但是,希望 OP 没有忽略这种滥用肯定会引起的编译器警告,然后提出他的问题,甚至没有提及它。
        • @JohnBollinger ,添加了关于警告的注释。
        • 将字符串数组设为 typedef / struct 会更好吗,因此您只需定义一次(如果您更改大小等,则需要进行单点更改)然后定义函数作为接受该类型的变量(或指向它的指针)?
        【解决方案6】:

        为什么要检查是否遇到了两次 'r' 字符? (在两个功能中) 检查一次就足够了。

        检测字符的函数,以及删除字符的函数?

        我会这样做的:

        #include <string.h>
        #include <stdio.h>
        
        void    convertStrings(char *line);
        void    removeChar(char *str);
        
        int     main(int argc, char *argv[]) {
            if (argc == 2)
            {
                printf("%s\n", argv[1]);
                convertStrings(argv[1]);
                printf("%s\n", argv[1]);
            }
            return (0);
        }
        
        void    convertStrings(char *line)
        {
            for (int i = 0; line[i] != '\0'; i++)
            {
                if (line[i] == 'r') removeChar(&(line[i]));
            }
        }
        
        void    removeChar(char *str)
        {
            int     i;
        
            i = 0;
            while (str[i] != '\0')
            {
                str[i] = str[i + 1];
                i++;
            }
        }
        

        但这是另一种只有一个功能的解决方案:

        void convertStringsbis(char *line)
        {
            int     delta;
            int     i;
        
        
            i = 0;
            delta = 0;
            while (line[i++ + delta] != '\0')
            {
                if (line[i + delta] == 'r')
                    delta++;
                line[i] = line[i + delta];
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-02
          • 1970-01-01
          • 2022-01-09
          • 2011-12-10
          相关资源
          最近更新 更多