Как исправить ошибку сегментации при попытке сканирования строки? - PullRequest
0 голосов
/ 02 мая 2019

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

const char letters[8][5] = {"ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"};

int main()
{
  int userNum[7];
  char userFile[25];
  printf("Please enter the phone number you want to process with no added 
characters or spaces: ");
  scanf("%d", &userNum);
  printf("Enter the file name (including extension and less than 25 
characters) that you would like to write to.\n");
  scanf("%s", userFile); //This is where I think the seg fault is happening
  printf("Test"); //Because this doesn't print

  FILE* file_ptr;
  char fileName[17];
  sprintf(fileName, "%s", userFile);
  file_ptr = fopen(fileName, "w");

  findWordsHelper(userNum, 7);
}

//Adding this function and the one after is what made the program start 
//giving said seg fault
void findWords(int userNum[], int digit, char words[], int n)
{
    printf("Test. n = %d", n);
    int i;
    if(digit == n)
    {
        printf("%s ", words);
        return;
    }

    for(i = 0; i < strlen(letters[userNum[digit]]); i++)
    {
        words[digit] = letters[userNum[digit]][i];
        findWords(userNum, digit+1, words, n);
        if(userNum[digit] == 0 || userNum[digit] == 1)
        {
            return;
        }
    }
}

void findWordsHelper(int userNum[], int n)
{
    printf("test");
    char result[n+1];
    result[n] = '\0';
    findWords(userNum, 0, result, n);
}

Ответы [ 3 ]

1 голос
/ 02 мая 2019

Я не в среде, которую я могу проверить, но я вижу несколько вещей. Во-первых, ваш тест printf не печатает, потому что if не имеет символа новой строки. Если вы не собираетесь вставлять один, позвоните fflush. * 1001 например *

  printf("test");
  fflush(stdout);

Во-вторых, использование scanf для чтения по номеру телефона показывает небольшое недопонимание того, как scanf будет рассматривать ввод как целое число. Для этого вам не нужен массив из 7 дюймов, потому что вы просто указали, что ввод не должен содержать никаких дополнительных символов. Таким образом, телефонный номер, такой как 345-6789, вводится как 3456789, который будет читаться как одно целое число, то есть 3 миллиона четыреста 56 тысяч семьсот 89. Это будет читаться как одно целое число. Я знаю, что вы хотите рассматривать их как отдельные числа, но scanf будет рассматривать их как 1 число, если они не разделены пробелами. Для чтения в один int этого будет достаточно:

...
int phoneNumber;
scanf("%d", &phoneNumber);  // <--- notice the & operator

EDIT Я читал справочную страницу для scanf(), и когда используется спецификатор %s, он должен вставить нулевой символ в строку. Таким образом, деталь, направленная на проверку возврата и обеспечение размещения символа '\0', неприменима.


РЕДАКТИРОВАТЬ 2 У меня был момент этим утром, и я должен был понять это. Я думаю, что у меня это есть. Что-то в функции findWords() выглядело немного подозрительно, и компиляция, сбой сегмента, и просмотр файла ядра показали, что это так. Именно эта строка в этой функции

    for(i = 0; i < strlen(letters[userNum[digit]]); i++)

В частности, это вызов strlen() с результатом использования userNum[] для индексации в letters[]. Как я и другие указали, scanf() не будет читать «номер телефона», такой как 3456789 (ввод как таковой) в 7 различных целочисленных значениях. Он читается как единственное целое и будет читаться в userNum[0] (и угадайте, что? digit = 0, когда произойдет ошибка). Это неудивительно, массив letters не содержит 3 миллиона 4ста 56 тысяч 7сот 89 единиц . (Предполагая, что введенное число - то, что я написал.)

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

0 голосов
/ 02 мая 2019
int main() {
  int userNum[7];
  char userFile[25];
  printf("Please enter the phone number you want to process with no added"
         " characters or spaces: ");

  printf("Enter the file name (including extension and less than 25 "
         " characters) that you would like to write to.\n");

  scanf("%s", userFile); //This is where I think the seg fault is happening

должно быть:

  scanf("%24s",userfile);

, который устанавливает ограничение в 24 символа для прочитанного.

 char fileName[17];
 sprintf(fileName, "%s", userFile);

Однако пользовательский файл может быть длинным 24 ... и это может соответствовать только 16, так и должно быть.

 sprintf(fileName, "%.16s", userFile);

, который отсекает любое переполнение.

0 голосов
/ 02 мая 2019

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

Вы можете либо выполнить fflush (stdout) сразу после вызова printf, либо использовать setvbuf с нулевым аргументом для принудительной отмены буферизации.

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

В-третьих, у вас определенно есть логическая проблема:

int userNum [7]; ... scanf ("% d", & userNum);

Похоже, вы ожидаете, что если пользователь введет "1234567", то каждый userNum [i] содержит одну цифру, но это не то, что происходит.

scanf будет рассматривать аргумент как указатель на int, например на 32-битном процессоре он поместил бы целочисленное значение 1234567 в первые 4 байта «userNum». Фактически, это может вызвать прямую ошибку, если процессор не может записать в целое число (16 или 32 бита) по невыровненному адресу. Поскольку userNum на самом деле является массивом, он может или не может быть выровнен для целого числа.

...