#c #string #realloc
#c #строка #перераспределение
Вопрос:
Впервые задаю вопрос здесь: ну, мне нужно взять исходную строку и удалить пробелы и цифры из строки, которая мне нужна, чтобы использовать точный объем памяти.
По какой-то причине строка в порядке в начале, но затем она выводит значения мусора:
исходная строка: "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", amp;all_Ex_in_loop) == 1)
do {
for (i = 1; i <= 3; i )
printf("Ex%d--->%dn", i, i);
printf("EXIT-->0n");
do {
select = 0;
printf("please select 0-3 : ");
scanf("%d", amp;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 amp;amp; select);
return 0;
}
/* Function definitions */
void Ex1() {
char input[] = "abcd2 34fty 78 jurt#";
char *temp = NULL;
temp = clearDigitsAndSpaces(input);
printf("%sn ", 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] != ' ' amp;amp; (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() {
}
Комментарии:
1. Это C или C ? Выберите один.
2. Комментарий без кода: вы завершили свою строку нулевым значением? Я думаю, что OP хотел пометить ее как C.
3. Просто используйте
shrink_to_fit
в вашем std::string.4. Как подсказывает @gsamaras, вам нужно:
int size = strlen(old_string) 1;
разместитьnul
терминатор. (strlen
Возвращаемое значение не включает его.)5. Не забудьте посчитать символ, заканчивающийся NUL, таким образом
strlen(...) 1
, и не забудьте скопировать его в конце…
Ответ №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] != ''; i ) {
if (src[i] != ' ' amp;amp; !(src[i] >= '0' amp;amp; src[i] <= '9'))
size ;
}
new_string = malloc(size);
if (new_string) {
size_t j = 0;
for (size_t i = 0; src[i] != ''; i ) {
if (src[i] != ' ' amp;amp; !(src[i] >= '0' amp;amp; src[i] <= '9'))
new_string[j ] = src[i];
}
new_string[j] = ''; // set the null terminator
}
return new_string;
}
Ответ №2:
Во-первых: вам нужно понимать разницу между длиной строки C и размером строки C. Длина не включает нулевой ограничитель. Размер имеет значение. Итак, этот фрагмент:
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));
(обратите внимание, что если вы используете Unicode в Windows с wchar_t
вместо char
, то размер в байтах в два раза больше длины, плюс 2 — каждый символ равен двум байтам, а также нулевой ограничитель, он же ‘sentinel’)
Во-вторых: я бы посоветовал вам использовать круглые скобки, чтобы четко указать намерение. Это может быть не «абсолютно необходимо», но не будет никаких сомнений в намерении, когда кто-то другой прочитает ваш код. Также избегайте многократного индексирования одного и того же. Изменить:
if (old_string[i]!=' ' amp;amp; (old_string[i] > '9' || old_string[i]< '0'))
Для:
char oldChar = old_string[i];
if ((oldChar != ' ')
amp;amp; ((oldChar > '9') || (oldChar < '0'))
)
Наконец, вам нужно поместить нулевой символ в конце. Вам не нужно перераспределять; просто используйте не весь буфер. Изменить:
new_string = (char*)realloc(new_string, size-1);
Для:
new_string[j ] = '';
// PS: if you really want to realloc, then add "new_string = (char*)realloc(new_string, j);" after writing the null character.
Также — если вы измените malloc
на calloc
, вам не нужно будет писать нулевой ограничитель, поскольку весь буфер будет обнулен до того, как вы скопируете в него что-либо.
Кроме того, я бы добавил проверку защитного предела в i
в цикле while, чтобы убедиться, что он не может продолжаться до бесконечности.