Данная тема создана мною, чтобы продемонстрировать, как не следует и как следует писать код на
C, на примере вопроса начинающего программиста
Can't figure out what's wrong with my code :\ (Array subtraction in C) на сайте
Stackoverflow.
Как следует из вопроса, требуется написать функцию, которая заполняет массив на основе разницы значений элементов двух других массивов, пока в первом из исходных массивов не встретится значение
-1, которое также должно быть записано в целевой массив. Пои этом если во-втором исходном массиве также встречается значение
-1, то следует использовать в операции элементы этого массива, начиная снова с нулевого индекса.
Вот как выглядит код начинающего программиста, представленный в вопросе.
void signalclear(int noise[64], int star[64], int clear[64]) {
int i = 0;
while (i < 63) {
i++;
if (star[ i ] == -1) {
continue;
}
if (noise[ i ] == -1) {
break;
}
clear[ i ] = noise[ i ] - star[ i ];
}
}
Очевидно, что код неверный, так как по, крайней мере, доступ к элементам массивов начинается с индекса
1, а не с
0, благодаря предложению в начале цикла
i++;
Также индексация массива
star не начинается снова с 0, когда в массиве встретился элемент со значением
-1.
К тому же функция не записывает значение
-1 в результирующий массив
clear, хотя, как следует из комментариев автора вопроса к своему вопросу, это значение также должно быть занесено в результирующий массив. То есть это граничное значение, определяющее число актуальных элементов в результирующем, а также в двух исходных массивах.
Делая рефакторинг кода, начнем с того, что в данном объявлении функции
void signalclear(int noise[64], int star[64], int clear[64]);
магическое число
64 не играет никакой роли и не имеет смысла. Во-первых, так как параметры массивов упорядочиваются компилятором к указателям на элементы массива. То есть, например, данные три объявления функции с одним и тем же именем объявляют одну и ту же функцию
void signalclear( int noise[64], int star[64], int clear[64] );
void signalclear( int noise[10], int star[20], int clear[39] );
void signalclear( int noise[], int star[], int clear[] );
и эквивалентны следующему объявлению функции
void signalclear( int *noise, int *star, int *clear );
Во-вторых, так как в массивах используется граничное значение
-1, по которому определяется число актуальных элементов в массивах, то размерность самих массивов не имеет значения. Очевидно предполагается, что результирующий массив достаточно велик, чтобы включить в себя все генерируемые элементы на основе двух исходных массивов согласно алгоритму.
Так как массивы
noise и
star не изменяются в функции, то их следует объявить с квалификатором
const.
Далее в
C результирующий массив обычно объявляется первым параметром, а исходные массивы объявляются последующими параметрами. Смотрите. например, объявления строковых функций в
<string.h>.
Кроме того, желательно, чтобы каждая функция предоставляла как можно больше полезной информации пользователю функции. В данном конкретном случае было бы разумно, чтобы функция возвращала число актуальных элементов, включая граничное значение, в результирующем массиве.
Итак, согласно вышеперечисленным замечаниям, данную функцию следовало бы объявить как
size_t signalclear( int *clear, const int *noise, const int *star );
Относительно используемого в функции алгоритма следует сделать одно замечание. Массив
star в общем случае может содержать лишь один актуальный элемент - само граничное значение, то есть
-1. В этом случае только оно и следует быть записано в результирующий массив, так как бессмысленно каждый раз возвращаться к индексу 0 для массива
star, так как других элементов в массиве нет, и мы всегда будет снова и снова попадать на значение
-1 в массиве
star.
С учетом сказанного функция может быть определена, как это показано в нижеприведенной демонстрационной программе.
#include <stdio.h>
size_t signalclear( int *clear, const int *noise, const int *star )
{
size_t n = 0;
if ( star[ 0 ] != -1 )
{
for ( size_t i = 0; noise[ n ] != -1; i++, n++ )
{
if ( star[ i ] == -1 ) i = 0;
clear[ n ] = noise[ n ] - star[ i ];
}
}
clear[ n++ ] = -1;
return n;
}
int main( void )
{
enum { N = 64 };
int noise[N] = { 20, 20, 20, 20, 30, 30, 30,-1 };
int star[N] = { 0, 5, 10, 15, -1 };
int clear[N];
size_t n = signalclear( clear, noise, star );
printf( "There are %zu elements in the array clear: ", n );
size_t i = 0;
do
{
printf( "%d ", clear[ i ] );
} while ( ++i != n );
putchar( '\n' );
}
Вывод программы на консоль для указанных в программе тестовых массивов будет:
There are 8 elements in the array clear: 20 15 10 5 30 25 20 -1
Как видно из вывода программы в массиве
clear будет ровно столько элементов, сколько актуальных элементов содержится в массиве
noise, включая элемент с граничным значением
-1.
И последнее замечание к результирующей реализации функции
signalclear.
Желательно для граничного значения ввести именованную константу. Например,
size_t signalclear( int *clear, const int *noise, const int *star )
{
const int SENTINEL = -1;
size_t n = 0;
if ( star[ 0 ] != SENTINEL )
{
for ( size_t i = 0; noise[ n ] != SENTINEL; i++, n++ )
{
if ( star[ i ] == SENTINEL ) i = 0;
clear[ n ] = noise[ n ] - star[ i ];
}
}
clear[n++] = SENTINEL;
return n;
}