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

В чем разница между строкой и введенной пользователем строкой в ​​C

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

Я нашел и использовал:

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

int main()
{

char *string, *found;

string = strdup ("1/2/3");
printf("Orig: '%s'\n",string);

while ((found = strsep(&string,"/")) != NULL )
  printf ("%s\n",found);

return (0);
}

и это печатает токены по одному.

Затем, когда я пытаюсь перейти к введенной пользователем строке:

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

int main()
{
  char string[13],
  char *found, *cp = string;

  fprintf(stderr, "\nEnter string: ");
  scanf("%12s",string);
  printf("Original string: '%s'\n",string);

  while((found =  strsep(&cp,"/,-")) != NULL )
    printf("%s\n",found);

  return(0);
}

Я получаю ошибку seg. Я понимаю основы указателей, массивов и строк, но явно что-то упускаю, и мне бы хотелось, чтобы кто-нибудь сказал мне, что это такое!

Кроме того, если я изменю printf("%s\n",found); на printf("%i\n",found);, я верну несколько нежелательных целых чисел, но всегда правильную сумму, например. Если я ввожу 1/2/3, я получаю три строки целых чисел, 1111/2222 я получаю две строки.

Спасибо!

-Edit- Возникла дополнительная проблема с strsep, подробно описанная здесь. Спасибо всем.

20.03.2018

  • Вам необходимо выделить место для пользовательской строки. Строковый литерал знает, какова его длина. 20.03.2018
  • Похоже, есть парень, который массово минусует, не объясняя почему. Прохладный. Это поможет улучшить нас (потому что я не понимаю, почему за меня проголосовали). 20.03.2018
  • Спасибо за ответы на все вопросы. Я помню, как читал об этом, так что просто оборачиваю голову. В то же время, я пробовал все предложения исправить размер, но я все еще получаю ошибку seg! Обновление вопроса, чтобы отразить это. 20.03.2018
  • Кроме того, я еще не проголосовал за чей-либо ответ, поэтому обязательно сделаю это, как только все пойму. Надеюсь, это поможет противостоять даунвотеру! 20.03.2018
  • Обновление. Я изменил спецификатор в printf на printf("%p\n",found); и получил три выходных адреса, поэтому идентификатор strsep выполняет свою работу. 20.03.2018

Ответы:


1

В первом фрагменте кода string присваивается возвращаемое значение strdup, которое выделяет пространство для дублирования строки и возвращает указатель на это выделенное пространство.

Во втором фрагменте кода string неинициализируется при передаче в scanf, поэтому scanf считывает недопустимое значение в этом указателе и пытается его разыменовать. Это вызывает неопределенное поведение, которое в данном случае проявляется как сбой.

Вам нужно выделить место для строки пользователя. Простой способ сделать это — создать массив заданного размера:

char string[80];

Затем сообщите scanf, сколько символов он может прочитать:

 scanf("%79s",string);
20.03.2018
  • Спасибо, очень красиво представленный ответ, который напомнил мне о том, как работают указатели. По какой-то причине строка не печатается даже после исправления длины string! 20.03.2018
  • @William Если у вас cp объявлено как char *, это должно работать. В вашем примере в настоящее время он имеет значение char. 20.03.2018
  • Большое спасибо за ваше время и вклад. Нет, это была моя опечатка в вопросе, у меня в коде была *. Для ясности я думаю, что начну новый вопрос, касающийся этой другой проблемы, и оставлю это для исходной ошибки. 21.03.2018

  • 2

    Различия между двумя случаями:

    1. В первом случае string указывает на допустимую память, выделенную strdup, а во втором случае вы пытаетесь прочитать недопустимую память.

    2. Первый случай — хорошее поведение, а второй — причина неопределенного поведения.

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

    char *string,*found;
    string = malloc(100); // Make it large enough for your need.
    fprintf(stderr, "\nEnter string: ");
    scanf("%99s",string);
    

    or

    char string[100], *found;
    fprintf(stderr, "\nEnter string: ");
    scanf("%99s",string);
    

    Убедитесь, что вы освободили динамически выделенную память. В противном случае ваша программа теряет память.

    20.03.2018
  • Спасибо, я помню, теперь указатель идет на то, что было в памяти. Как ни странно, я все еще получаю ошибки seg даже после выделения длины. 20.03.2018
  • Вы передаете неправильный аргумент в strsep. Используйте char* cp = string; while((found = strsep(&cp,"/,-")) != NULL ). 20.03.2018
  • Ах да, я вижу это! Теперь код проходит мимо строки strsep (я добавил после нее простую строку printf), но в строке printf("%s\n",found); возникают ошибки seg. Что-то я до сих пор не замечаю! 20.03.2018
  • @William, я не могу объяснить, почему это происходит. 20.03.2018

  • 3

    Вы должны выделить память для строки пользовательского ввода.

    Первый вариант статический

    char string[256];

    и второй вариант динамически использует функцию malloc()

    char *string;
    
    string = (char*) malloc(256 * sizeof(char));
    if (string == NULL)
       {
       //error
       }
    

    Не забудьте в конце освободить выделенную память

    free(string);
    
    20.03.2018
  • какова цель такого malloc? Вы можете просто ввести char string[256] и результат будет таким же. 20.03.2018
  • Это всего лишь второй способ выделения памяти. Что случилось с этим? 20.03.2018
  • а в исходном коде первая строка обрабатывается функцией malloc с помощью strdup. 20.03.2018
  • Потому что в вашем примере вы, кажется, освобождаете его сразу после этого. Итак, какова цель этого распределения? Это усложняет код ни за что. Но я не читал, что вы ставите статическую форму, извините. (и sizeof(char) == 1, так что не нужно его добавлять, и если вам действительно нужен sizeof, лучше иметь sizeof(*string)) 20.03.2018
  • Вы правы в том, что sizeof(char) равен 1, просто чтобы быть типичным и не рисковать запутать ОП. Я добавил free(), чтобы не забыть поставить его в конце кода, чтобы освободить выделенную память. 20.03.2018

  • 4

    В случае пользовательского ввода строки у вас нет памяти, выделенной для строки указателя. В первом случае strdup выделяет память для указателя строки, а во втором случае у вас нет памяти, связанной с указателем строки. приводит к сегфоулту. сначала выделите память с помощью malloc, а затем используйте scanf.

    20.03.2018

    5

    Вы не выделили необходимое место! У вас должно быть место в памяти для записи. Вы можете иметь его статически "char string[256]" или динамически с распределением.

    В вашем первом примере вы используете «strdup», который выполняет malloc, но scanf не будет выделять вам память.

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

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

    20.03.2018

    6

    символьная строка[13] символ cp=строка

    Здесь cp — переменная типа char и 1 байт выделенной памяти

    Он не сможет хранить массив символов из 13 символов, который будет составлять 13 байтов, и из-за этого вы получаете ошибку сегментации.

    20.03.2018
  • Хорошо, это интересно, я думал, что char *cp был указателем? Когда я меняю аргумент printf("%s\n",found); на %i, я получаю (случайные) целые числа и возвращаю правильное количество токенов, которое я ожидаю, поэтому я думал, что вся строка передается правильно 20.03.2018

  • 7

    Причина очень проста. Ваша переменная string является указателем char, и вам нужно выделить для нее память для хранения строки. Возможно, в вашем первом случае strdup ("1/2/3"); возвращает строку, а ваш char pointer *string указывает на строку, возвращаемую функцией strdup, и это причина, по которой вы не получаете ошибка сегментации в первом случае. Даже в первом случае вы можете получить ошибку сегментации, если введете очень длинную строку.

    поэтому выделите достаточно памяти для указателя string, как показано ниже во втором примере, и это решит вашу проблему: -

     char *string = malloc(50);// here malloc will allocate 50 bytes from heap
    
    20.03.2018
    Новые материалы

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

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

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

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

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

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

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