【问题标题】:How to shrink string by using Realloc如何使用 Realloc 收缩字符串
【发布时间】:2020-12-18 09:54:23
【问题描述】:

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

由于某种原因,字符串开头很好 但随后它会打印垃圾值:

原始字符串:"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 还是 C++?选择一个。
  • No-code-look 评论:您是否 NULL 终止了您的字符串?我认为 OP 打算将其标记为 C.
  • 只需在您的 std::string 上使用 shrink_to_fit
  • 正如@gsamaras 所暗示的,您需要:int size = strlen(old_string) + 1; 以容纳nul 终止符。 (strlen 返回值不包括它。)
  • 不要忘记计算 NUL 终止字符,即 strlen(...)+1 并且不要忘记在末尾复制它...

标签: c string realloc


【解决方案1】:

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

您可以避免使用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] != '\0'; 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] != '\0'; i++) {
            if (src[i] != ' ' && !(src[i] >= '0' && src[i] <= '9'))
                new_string[j++] = src[i];
        }
        new_string[j] = '\0';  // set the null terminator
    }
    return new_string;
}

【讨论】:

    【解决方案2】:

    首先:你需要了解C-string的length和C-string的size之间的区别。长度不包括空终止符。大小可以。所以这个sn-p:

    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 - 每个字符是两个字节,以及空终止符又名“哨兵”)


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

    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++] = '\0';
    
    // 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 添加一个防御性限制检查,以确保它不会无限期地继续下去。

    【讨论】:

      猜你喜欢
      • 2011-04-16
      • 1970-01-01
      • 2017-04-12
      • 2016-10-25
      • 2016-08-22
      • 2016-04-09
      • 1970-01-01
      • 2011-11-20
      • 2022-01-22
      相关资源
      最近更新 更多