Nano Hash - криптовалюты, майнинг, программирование

Почему malloc не может работать с strcpy?

char * removeChar(char * str, char c){
    int len = strlen(str);
    int i = 0;
    int j = 0;
    char * copy = malloc(sizeof(char) * (len + 1));
    while(i < len){
        if(str[i] != c){
            copy[j] = str[i];
            j++;
            i++;
        }else{
            i++;
        }
   }

    if(strcmp(copy, str) != 0){
        strcpy(str,copy);

    }else{
        printf("Error");
    }
    return copy;
}




int main(int argc, char * argv[]){
    char str[] = "Input string";
    char * input;
    input = removeChar(str,'g');
    printf("%s\n", input);
    free(input);
    return 0;
}

Я не знаю, почему каждый раз, когда я пытаюсь запустить его, он всегда говорит неинициализированная переменная и застревает в строке strcpy и строке printf.

По сути, эта функция берет строку и символ и удаляет этот символ из строки (потому что я изучаю malloc, поэтому я написал такую ​​функцию).


  • Мне кажется, что после конца блока if(strcmp(copy, str) != 0) отсутствуют как минимум две строки кода. Пожалуйста, добавьте их. (Вы можете отредактировать свой вопрос — видите маленькое серое слово «редактировать» под синей буквой «с» в рамке? Это кнопка. Да, правда.) 19.06.2017
  • Я думаю, вы забыли установить последний байт строки в NUL (\0). 19.06.2017
  • Я получаю не это предупреждение, а другое ~ предупреждение C4715: 'removeChar': не все пути управления возвращают значение. Но, поскольку мне пришлось добавить отсутствующий }, возможно, я поместил его не в то место. 19.06.2017
  • Я также не получаю никаких предупреждений о неинициализированных переменных. В этом коде есть несколько мест, где я бы не сделал этого таким образом, и недостающая пара строк является проблемой, но единственная реальная ошибка, которую я вижу, это та, на которую указали Александр и Кром. 19.06.2017
  • @Нина Лю Функция не имеет смысла. Опишите в вопросе, чего вы пытаетесь достичь. 19.06.2017
  • Вы также должны скопировать последний байт, который используется для закрытия строки, и его значение равно 0. Тогда while должно быть while ( i <= len ). Кроме того, malloc должен выделить sizeof(char)*len +1. 19.06.2017
  • ... if внутри while не нуждается в else... переменная i может увеличиваться для каждого цикла. 19.06.2017
  • @VladfromMoscow удаляет указанный символ из входной строки. Это работает, если это хотя бы последнее... 19.06.2017
  • @gsamaras Нет, это не так. Функция не имеет никакого смысла. 19.06.2017

Ответы:


1

После цикла while выполните:

copy[j] = '\0';

чтобы NULL завершить вашу строку; таким образом он может работать с методами, происходящими из <string.h>, которые предполагают, что строка завершается нулем.


PS: одно из предупреждений, которое вы должны увидеть, касается того, что вы не должны возвращать copy в своей функции в любом случае, потому что теперь, если условие оператора if неверно, ваша функция не вернет что-то действительное, поэтому добавьте это:

return copy;

в конце вашей функции (которая теперь исправлена ​​вашим редактированием).

Кроме этого, единственное предупреждение, которое вы все равно должны получить, касается неиспользуемых аргументов main(), ничего больше:

prog.c: In function 'main':
prog.c:32:14: warning: unused parameter 'argc' [-Wunused-parameter]
 int main(int argc, char * argv[]){
              ^~~~
prog.c:32:27: warning: unused parameter 'argv' [-Wunused-parameter]
 int main(int argc, char * argv[]){
                           ^~~~
19.06.2017
  • Придирка: NULL — это указатель. Строки заканчиваются NUL, только с одной буквой L. 19.06.2017
  • @zwol: вот почему сейчас почти исключительно говорят об нулевом завершении. Менее запутанно. 19.06.2017

  • 2

    При копировании байтов из str в copy вы не добавляете завершающий нулевой байт в конце. В результате strcmp читает скопированные символы в унифицированную память, возможно, за конец выделенного блока памяти. Это вызывает неопределенное поведение.

    После цикла while добавьте завершающий нулевой байт в copy.

    Кроме того, вы никогда не вернете значение, если блок if в конце имеет значение false. Для этого вам нужно что-то вернуть, возможно, скопированную строку.

    char * removeChar(char * str, char c){
        int len = strlen(str);
        int i = 0;
        int j = 0;
        char * copy = malloc(sizeof(char) * (len + 1));
        while(i < len){
            if(str[i] != c){
                copy[j] = str[i];
                j++;
                i++;
            }else{
                i++;
            }
        }
        //  add terminating null byte
        copy[j] = '\0';
    
        if(strcmp(copy, str) != 0){
           strcpy(str,copy);
        }
        // always return copy
        return copy;
    }
    
    19.06.2017

    3

    Вы никогда не инициализировали ввод, и некоторые компиляторы не замечают, что значение никогда не используется перед строкой

    input = removeChar(str, 'g');
    

    в вашем коде. Поэтому они выдают диагностику просто для уверенности.

    strcpy(str, copy)
    

    застревает в вашем коде, так как копия никогда не получает закрывающий 0 байт и поэтому зависит от недетерминированного содержимого вашей памяти в момент выделения резервной копии памяти, как долго будет работать strcpy и получите ли вы в конечном итоге SIGSEGV (или аналогичный).

    strcpy будет зацикливаться, пока не найдет 0 байт в вашей памяти.

    19.06.2017

    4

    Для начала, чтобы удалить символ из строки, нет необходимости динамически создавать массив символов, а затем копировать этот массив в исходную строку.

    Либо вы должны написать функцию, которая действительно удаляет указанный символ из строки, либо функцию, которая создает новую строку на основе исходной строки, исключая указанный символ.

    Это просто плохой дизайн, который только смущает пользователей. То есть функция слишком сложна и использует избыточные функции, такие как malloc, strlen, strcmp и strcpy. И на самом деле у него есть побочный эффект, который не очевиден. Кроме того, используется некорректный тип int для длины строки вместо типа size_t.

    Что касается реализации вашей функции, то вы забыли добавить завершающий ноль '\ 0' к строке, построенной в динамически выделенном массиве.

    Если вы действительно хотите удалить символ из строки, функция может выглядеть так, как показано в демонстрационной программе.

    #include <stdio.h>
    
    char * remove_char(char *s, char c)
    {
        char *p = s;
    
        while (*p && *p != c) ++p;
    
        for ( char *q = p; *p++; )
        {
            if (*p != c) *q++ = *p;
        }
    
        return s;
    }
    
    int main( void )
    {
        char str[] = "Input string";
    
        puts(str);
        puts(remove_char(str, 'g'));
    
        return 0;
    }
    

    Вывод программы

    Input string
    Input strin
    

    Если вы изучаете функцию malloc и хотите ее использовать, вы в любом случае должны попытаться реализовать правильный дизайн.

    Чтобы использовать malloc, вы можете написать функцию, которая создает новую строку на основе исходной строки, исключая указанный символ. Например

    #include <stdio.h>
    #include <stdlib.h>
    
    char * remove_copy_char(const char *s, char c)
    {
        size_t n = 0;
    
        for (const char *p = s; *p; ++p)
        {
            if (*p != c) ++n;
        }
    
        char *result = malloc(n + 1);
    
        if (result)
        {
            char *q = result;
    
            for (; *s; ++s)
            {
                if (*s != c) *q++ = *s;
            }
    
            *q = '\0';
        }
    
        return result;
    }
    
    int main( void )
    {
        char *str = "Input string";
    
        puts(str);
    
        char *p = remove_copy_char(str, 'g');
    
        if ( p ) puts(p );
    
        free(p);
    
        return 0;
    }
    

    Вывод программы будет таким же, как указано выше.

    Input string
    Input strin
    

    Обратите внимание на объявление функции

    char * remove_copy_char(const char *s, char c);
                            ^^^^^^
    

    В этом случае исходная строка может быть строковым литералом.

    char *str = "Input string";
    
    19.06.2017
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..