Ошибка сегментации при записи программы телефонного номера

#c #string #segmentation-fault #scanf

#c #строка #ошибка сегментации #scanf

Вопрос:

Я пишу программу на C, которая предлагает пользователю ввести номер телефона в форме (xxx) xxx-xxxx, а затем отображает номер в формате xxx.xxx.xxxx. Вот пример:

 Enter a phone number [(xxx) xxx-xxxx]: (404)817-6200
You entered the data 404.817.6200
  

Я создал две строки, одну для хранения номера телефона со скобками и знаками «-«, а другую — пустую. Я хочу добавить каждый символ в пустую строку, изменив ‘)’ и ‘-‘ на ‘.’. Вот мой код:

 #include <stdio.h>
int main(void){
    char num[15];
    char phone[13];

    int i = 1;
    int j = 0;
    printf("Please, enter your phone number in the format (xxx)xxx-xxxx:");
    scanf("n%s", num);
    while(num != ''){
        if(num[i] == ')' || num[i] == '-'){
            phone[j] = '.';
        }else{
            phone[j] = num[i];
        }
        i  ;
        j  ;
        
    }
    printf("n%s",phone);
}
  

Когда я запускаю программу, она выдает сообщение об ошибке, в котором говорится:

 Segmentation fault
  

Может кто-нибудь объяснить, почему это происходит и как предотвратить это в будущем?

Комментарии:

1. while(num != '') -> while(num[i] != '')

2. Это сработало! Можете ли вы это объяснить?

3. @Romanmukosieev ваш компилятор должен был предупредить вас. num это массив, но вам нужен только один элемент массива.

4. Вы не копируете нулевой терминатор в phone .

5. Что касается того, почему это сработало, это та же причина, по которой вы делаете num[i] == ')'

Ответ №1:

Я вижу три проблемы в вашей программе:

(1) while(num != '') должно быть while(num[i] != '' . num является массивом (и никогда не будет сравниваться равным '' , поэтому вы получаете бесконечный цикл и превышаете границы массива.

(2) вам нужно не менее 14 байт для phone (только на один меньше num, а не на два меньше)

(3) вам нужно записать символ завершения строки в phone ; в printf("n%s",phone); противном случае снова превысит границы phone ; например:

 }
phone[j] = '';
printf("n%s",phone);`
  

Комментарии:

1. Если выходные данные действительно всегда xxx.xxx.xxxx имеют формат, то 13 является достаточным размером для phone … и num должно быть только 14.

Ответ №2:

Когда вы ссылаетесь на имя переменной массива в C, без добавления оператора [] (index), вы (фактически) ссылаетесь на адрес первого элемента этого массива. Это никогда не будет равно нулю (или NULL ) для массива, объявленного как локальная переменная, поэтому сравнение num с нулем ( '' ) в вашем while цикле никогда не будет истинным, и цикл будет выполняться без остановки, пока вы не попытаетесь прочитать или записать недопустимый адрес, после чего программа завершится сбоем.

При включенных предупреждениях компилятора вы должны увидеть что-то вроде следующего (генерируется clang-cl):

предупреждение: сравнение указателя с нулевой символьной константой; вы имели в виду сравнение с NULL? [-Wpointer-compare]
предупреждение: сравнение массива ‘num’, не равного нулевому указателю, всегда верно [-Wtautological-pointer-compare]

Вместо этого вам следует сравнить «текущий» элемент (по индексу i ) с nul символом ( '' ), чтобы проверить конец строки:

     while (num[i] != '') {// Check character at position "i"
        // rest of your loop ...
  

Вы также должны убедиться, что ваша phone строка правильно nul завершается (хотя некоторые компиляторы инициализируют массив нулем, не полагайтесь на это). Вы можете сделать это либо путем добавления инициализатора к объявлению phone :

     char phone[13] = { 0 }; // Will set all elements to zero
  

или путем добавления nul разделителя сразу после окончания вашего while цикла:

         // body of while loop
        // ...
    }
    phone[j] = ''; // Append the terminator