Программа предназначена для удаления «-» из введенного кода ISBN, например. Вводится "978-123456-789" и выводится "978123456789". Вместо этого я получаю "978123456789978123456789" - он печатает это дважды. Может кто-нибудь объяснить мне, почему? Спасибо
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main(void)
{
char ISBN[16], arrayClean[12];
int i,j,k,a;
printf("Enter your ISBN: ");
scanf("%s",&ISBN);
for(i=0; i<=13; i++)
{
a = ISBN[i] - 48;
if (a==-3)
{
for(j=i;j<=13;j++)
{
k++;
ISBN[j]=ISBN[j+1];
}
k=0;
i=0;
}
}
for(i=0; i<=11; i++)
arrayClean[i]=ISBN[i];
printf("%s",arrayClean);
return 0;
}
Что отмечает конец строки? Где в вашей программе вы его устанавливаете?
scanf("%s", &ISBN) неверен. Это должен быть scanf("%s", ISBN). Для чего используется переменная «k»? Зачем странное и бессмысленное вычитание 48 и сравнение с -3? Просто сравните с «-». Много «магических чисел». 16, 12, 13, 11.
У вас, кажется, 12 символов в числе (исключая пунктир. 14, считая их).
Таким образом, ваши циклы не могут обрабатывать символы от 0 до 11 вывода и символы от 0 до 13 ввода. Это забывает о терминале '\ 0', который также должен быть там, на выходе, в позиции 12.
(Если вы на 100% уверены, что будет 12 символов, то вы можете решить эту проблему, просто добавив arrayClean[12]=0
в конце, непосредственно перед печатью. Но это было бы плохой идеей. Поскольку это будет полагаться на то, что набирает пользователь ).
Кроме того, даже объявления вашего массива «arrayClean» не учитывают необходимость терминала '\0'
. Вам нужно 13 байт для хранения строки из 12 символов.
Некоторые другие замечания:
Ваше использование scanf("%s", &ISBN);
опасно.
Прежде всего, это должно быть scanf("%s", ISBN);
. Что вам нужно передать scanf
, так это адрес, где хранить то, что он читает. Когда вы читаете один int x;
, то, действительно, вы должны scanf("%d", &x);
, чтобы scanf сохранял результат по адресу, где хранится x. Но для строки ISBN
уже является адресом (адресом символов ISBN[0]
, ISBN[1]
, ...). Так что не стоит передавать адрес ISBN.
Что вас здесь спасает, так это то, что, поскольку ISBN не является переменной (это массив, то есть постоянный указатель), в C &ISBN
и ISBN
это одно и то же в этом самом контексте. Так что случайно срабатывает.
Но если бы ISBN был переменной (например, char *
, выделенной вместе с malloc
), то такое использование привело бы к ошибкам памяти. Итак, вы должны взять за привычку переходить не &ISBN
к scanf
, а ISBN
.
Другая проблема с той же строкой: при сканировании вы не можете доверять пользователю вводить точное количество байтов, которое вы ожидаете. Здесь, если пользователь вводит 16 или более байтов, эти байты будут записаны в любую память после 16 байтов ISBN
. Что вызовет очень серьезную проблему. Даже защитные, если пользователь делает это специально, чтобы перезаписать другие переменные и даже коды на какой-то архитектуре.
Итак, эмпирическое правило: никогда scanf("%s", ...)
.
Всегда применяйте ограничение на количество байтов, которые может прочитать scanf. scanf("%15s", ...)
например.
Вы не нуль, завершающий строку. Вы копируете только 12 символов из ISBN в arrayClean. Вам нужно добавить нулевой терминатор в конец arrayClean
. Вы можете сделать это, добавив arrayClean[12] = '\0';
после цикла for.
char ISBN[16], arrayClean[12];
int i, j, k, a;
printf("Enter your ISBN: ");
scanf("%s", &ISBN);
for (i = 0; i <= 13; i++)
{
a = ISBN[i] - 48;
if (a == -3)
{
for (j = i; j <= 13; j++)
{
k++;
ISBN[j] = ISBN[j + 1];
}
k = 0;
i = 0;
}
}
for (i = 0; i <= 11; i++)
arrayClean[i] = ISBN[i];
arrayClean[12] = '\0';
printf("%s", arrayClean);
Вы прошлись по программе с помощью отладчика, чтобы увидеть, какие значения имеет каждая переменная?