简体   繁体   English

使用C从字符串中删除连续的重复字符

[英]Removing consecutive repeated characters from string using C

I'm trying to remove consecutive repeated characters from a given string. 我正在尝试从给定的字符串中删除连续的重复字符。

Example: 例:

bssdffFdcrrrtttii ***# bssdffFdcrrrtttii ***#

output is supposed to be: 输出应该是:

bsdfFdcrti *# bsdfFdcrti *#

This code doesn't work and only prints the first char (b), I want to learn about my mistake. 此代码无效,仅输出第一个字符(b),我想了解我的错误。 when I'm doing a printf test, it works but not for spaces. 当我进行printf测试时,它可以工作,但不能用于空格。 I think the problem might be with the new char array. 我认为问题可能出在新的char数组上。

void Ex6() {
    char* string[80];
    scanf("%s", &string);
    puts(removeDup(string));
}

char* removeDup(char *string) {
    int i, c = 0;
    char* newString[80];
    for (i = 0; i < strlen(string); i++) {
        if (string[i] != string[i + 1]) {
            newString[c++] = string[i];
        }
    }
    return newString;
}

There are several problems with your program: 您的程序有几个问题:

  • The declaration of newString should be char newString[80] , ie, an array of characters and not an array of pointers-to-characters, and likewise for the declaration in Ex6 . newString的声明应为char newString[80] ,即,一个字符数组,而不是一个指向字符的指针数组,同样对于Ex6的声明。
  • The call to scanf should then be scanf("%s", string) , since string is already the address of an array of characters, but... 然后,对scanf的调用应为scanf("%s", string) ,因为string已经是字符数组的地址,但是...
  • Use fgets to read a string from the user to ensure that you read whitespace, if it's important, and that the buffer is not exceeded. 使用fgets从用户读取字符串,以确保您读取空格(如果很重要),并且不超过缓冲区。
  • newString is allocated on the stack and so should not be returned to the caller. newString是在堆栈上分配的,因此不应返回给调用方。 It is better to do a char *newString = strdup(string) , or, slightly less sloppy, char *newString = malloc(strlen(string)+1) , which will call malloc for a block of memory sufficient to hold the original string, and thus the version without duplicates -- the comments rightly point out that this could be optimized. 最好做一个char *newString = strdup(string) ,或者稍微少一点草率的char *newString = malloc(strlen(string)+1) ,这将调用malloc以获得足以容纳原始字符串的内存块,因此没有重复的版本-注释正确地指出可以对其进行优化。 In principle, the caller, ie, Ex6 , must free the returned pointer to avoid a memory leak but it hardly matters in such a short program. 原则上,调用者(即Ex6 )必须free返回的指针,以避免内存泄漏,但是在如此短的程序中这无关紧要。
  • The result needs a null terminator: newString[c] = '\\0' . 结果需要一个空终止符: newString[c] = '\\0'

Otherwise, the removeDup function seems to work correctly. 否则, removeDup函数似乎可以正常工作。

So, putting all of that together: 因此,将所有这些放在一起:

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

char* removeDup(const char *string)
{
    size_t i, c = 0;
    size_t string_len = strlen(string);
    char *newString = malloc(string_len + 1);

    for (i = 0; i < string_len; i++) {
        if (string[i] != string[i + 1]) {
            newString[c++] = string[i];
        }
    }
    newString[c] = '\0';

    return newString;
}

#define MAX_STRING_LEN 80

void Ex6() {
    char string[MAX_STRING_LEN];
    char* result;

    if (fgets(string, MAX_STRING_LEN, stdin) != NULL) {
        result = removeDup(string);

        printf("%s", result);
        free(result);
    }
}

Finally, I agree with @tadman's comment. 最后,我同意@tadman的评论。 Since the input string must anyway be traversed to calculate the length, we may as well optimize the size of the result string: 由于无论如何都必须遍历输入字符串以计算长度,因此我们也可以优化结果字符串的大小:

char* removeDup(const char *string)
{
    size_t i, c = 0;
    char *newString;

    for (i = 0; string[i] != '\0'; i++)
        c += (string[i] != string[i + 1]);

    newString = malloc(c + 1);

    for (i = c = 0; string[i] != '\0'; i++) {
        if (string[i] != string[i + 1]) {
            newString[c++] = string[i];
        }
    }
    newString[c] = '\0';

    return newString;
}

There are quite a few issues in your program. 您的程序中有很多问题。 It wouldn't even compile let alone run. 它甚至不会编译,更不用说运行了。 Also, the most problematic issue is that you are returning a pointer to a local variable from a function that ceases its scope upon completion. 同样,最有问题的问题是,您正在从函数返回指向局部变量的指针,该函数在完成时会终止其作用域。 A simplified version of your program is as follows: 程序的简化版本如下:

void Ex6() 
{
   char string[80];
    scanf("%s", string);
        int i, c = 0;
    char newString[80];
    for (i = 0; i < strlen(string); i++) {
        if (string[i] != string[i + 1]) {
            newString[c++] = string[i];
        }
    }
    newString[c] = '\0';
    puts(newString);
}

You can do it with O(n) time and O(1) space, by modifying existing string: 您可以通过修改现有字符串来使用O(n)时间和O(1)空间来实现:

#include <stdio.h>

char* removeDup(char* input) {
        char* newTail = input, *oldTail = input;
        while (*oldTail) {
            if (*newTail == *oldTail) {
                ++oldTail;
            } else {
                *++newTail = *oldTail++;
            }
        }
    return newTail;
}

int main() {
   char string[] = "bssdffFdcrrrtttii ***#";
   char* newEnd = removeDup(string);
   char* tmp = string;
   while (tmp != newEnd) {
       printf("%c", *tmp++);
   }
   //Print the last char if string had any duplicates
   if(*tmp) {
       printf("%c", *tmp++);
   }
   return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM