如何使用 Realloc 缩小字符串

How to shrink string by using Realloc

第一次在这里提问: 好吧,我需要使用原始字符串 并从字符串中删除空格和数字 我需要使用准确数量的内存。

出于某种原因,字符串一开始没问题 但随后它打印垃圾值:

原始字符串:"abcd2 34fty 78 jurt#"
需要做什么:abcdftyjurt#

我的代码:

#define _CRT_SECURE_NO_WARNINGS

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

/* Function declarations */

/*-------------------------------------------------------------*/
void Ex1();
char* clearDigitsAndSpaces(char*);
/*-------------------------------------------------------------*/
void Ex2();

/*-------------------------------------------------------------*/
void Ex3();

/*-------------------------------------------------------------*/
/* Declarations of other functions */

int main() {
    int select = 0, i, all_Ex_in_loop = 0;
    printf("Run menu once or cyclically?\n(Once - enter 0, cyclically - enter other number) ");
    if (scanf("%d", &all_Ex_in_loop) == 1)
        do {
            for (i = 1; i <= 3; i++)
                printf("Ex%d--->%d\n", i, i);
            printf("EXIT-->0\n");
            do {
                select = 0;
                printf("please select 0-3 : ");
                scanf("%d", &select);
            } while ((select < 0) || (select > 3));
            switch (select) {
            case 1: Ex1(); break;
            case 2: Ex2(); break;
            case 3: Ex3(); break;
            }
        } while (all_Ex_in_loop && select);
        return 0;
}

/* Function definitions */

void Ex1() {
    char input[] = "abcd2 34fty    78 jurt#";
    char *temp = NULL;
    temp = clearDigitsAndSpaces(input);
    printf("%s\n ", temp);
    free(temp);
}

char *clearDigitsAndSpaces(char *old_string) {
    char *new_string;
    int count = 0;
    int i = 0;
    int j = 0;
    int size = strlen(old_string);
    new_string = (char *)malloc(size * sizeof(char));
    assert(new_string); /*Memory allocation check*/
    while (old_string[i]) {
        if (old_string[i] != ' ' && (old_string[i] > '9' || old_string[i] < '0')) {
            new_string[j++] = old_string[i];
        } else {
            //size -= 1;
            new_string = (char *)realloc(new_string, size - 1);
        }
        i++;
    }
    assert(new_string);
    //printf("%s", new_string);
    return new_string;
}

void Ex2() {
}

void Ex3() {
}

首先:你需要了解C-string的长度和[=的大小之间的区别46=]。该长度不包括空终止符。大小就可以了所以这个片段:

int size = strlen(old_string);
new_string = (char*)malloc(size * sizeof(char));

需要

int size = strlen(old_string) + 1;
new_string = (char*)malloc(size * sizeof(char));

(请注意,如果您在 Windows 中使用 Unicode,使用 wchar_t 而不是 char,则字节大小是长度的两倍,加上 2 - 每个字符是两个字节,以及空终止符又名 'sentinel')


其次:我建议你使用括号来明确意图。它可能不是“绝对必要的”,但是当其他人阅读您的代码时,其意图是毫无疑问的。还要避免重复索引同一事物。变化:

if (old_string[i]!=' ' && (old_string[i] > '9' || old_string[i]< '0'))

至:

char oldChar = old_string[i];
if ((oldChar != ' ') 
    && ((oldChar > '9') || (oldChar < '0'))
   )

最后,您需要在末尾放置一个空字符。你不需要重新分配;只是不使用所有的缓冲区。变化:

new_string = (char*)realloc(new_string, size-1);

至:

new_string[j++] = '[=15=]';

// PS: if you really want to realloc, then add "new_string = (char*)realloc(new_string, j);" after writing the null character.

此外 - 如果您将 malloc 更改为 calloc,您将不需要编写空终止符,因为在您向其中复制任何内容之前整个缓冲区将被清空。

此外,我会在while循环中对i添加防御限制检查,以确保它不会继续ad-infinitum。

您的代码中的问题是您必须为空终止符分配一个额外的字节。

您可以避免使用 realloc(),方法是首先扫描源字符串以确定分配大小,然后使用单独的循环来复制内容:

char *clearDigitsAndSpaces(const char *src) {
    char *new_string;
    size_t size = 1; // 1 extra byte for the null terminator.

    for (size_t i = 0; src[i] != '[=10=]'; i++) {
        if (src[i] != ' ' && !(src[i] >= '0' && src[i] <= '9'))
            size++;
    }
    new_string = malloc(size);
    if (new_string) {
        size_t j = 0;
        for (size_t i = 0; src[i] != '[=10=]'; i++) {
            if (src[i] != ' ' && !(src[i] >= '0' && src[i] <= '9'))
                new_string[j++] = src[i];
        }
        new_string[j] = '[=10=]';  // set the null terminator
    }
    return new_string;
}