2016-10-11 1 views
0

Следующая программа должна копировать элементы исходного массива в в целевых массивах, используя различные опорные указатель нотации в каждой функции:необъяснимые побочные эффекты функции на других несвязанных единиц в C

#include <stdio.h> 

void copy_arr(double [], const double [], int); 
void copy_ptr(double *, const double *, int); 
void copy_ptrs(double *, const double *, double *); 
void print_arr(const double *, const double *); 

int main(void) 
{ 
    double source[5] = { 0.1, 2.2, 4.3, 6.4, 8.5}; 
    double target1[5]; 
    double target2[5]; 
    double target3[5]; 

    copy_arr(target1, source, 5); 
    copy_ptr(target2, source, 5); 

    copy_ptrs(target3, source, source + 5); 

    print_arr(target1, target1 + 5); 
    print_arr(target2, target2 + 5); 
    print_arr(target3, target3 + 5); 

    return 0; 
} 

void copy_arr(double target[], const double source[], int num) 
{ 
    for (int i = 0; i < num; ++i) 
    target[i] = source[i]; 
} 

void copy_ptr(double *target, const double *source, int num) 
{ 
    for (int i = 0; i < num; ++i) 
    *(target+i) = *(source+i); 
} 

void copy_ptrs(double *target, const double *source, double *end) 
{ 
    for (; target < end; ++target, ++source) 
    *target = *source; 
} 

void print_arr(const double *start, const double *end) 
{ 
    while (start < end) 
    printf("%.1lf, ", *start++); 
    printf("\n"); 
} 

Это производит выходы как :

 
0.0, 0.0, 0.0, 0.0, 0.0, 
0.0, 0.0, 0.0, 0.0, 0.0, 
0.1, 2.2, 4.3, 6.4, 8.5, 

или мусор на месте нулей.

Однако, когда я случайно изменил функцию copy_ptrs на:

void copy_ptrs(double *target, const double *source, double *end) 
    { 
     for (; *target < *end; ++target, ++source) // notice the asterisks 
     *target = *source; 
    } 

Я получаю следующий вывод:

 
0.1 2.2 4.3 6.4 8.5 
0.1 2.2 4.3 6.4 8.5 
0.0 0.0 0.0 0.0 0.0 

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

Для повторной итерации: разыменование переменных target и end дает правильный выход для третьей функции, но «разрывает» предыдущие; и не делает этого нарушает свою соответствующую функцию. Я думаю, что разыменование указателей start и end - это правильный путь, потому что print_arr не разыгрывает их, а ведет себя так, как ожидалось (и, согласно моему пониманию, является правильным способом).

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

Я использую GCC 4.8.5 для Linux.

+0

Вы читаете неинициализированные данные из '* target'; все ставки не учитывают то, что вы получаете. –

+0

к моменту, когда цели будут прочитаны 'print_arr', они были скопированы с помощью функций' copy_'. –

+0

Проблема заключается во втором 'copy_ptrs()' и использовании '* target <* end'. Вы читаете '* target', прежде чем ему присваивается значение, и на самом деле' * end' также не имеет определенного значения. –

ответ

4

Самая большая проблема с copy_ptrs() является конечным условием:

void copy_ptrs(double *target, const double *source, double *end) 
{ 
    for (; target < end; ++target, ++source) 
    *target = *source; 
} 

Обратите внимание, что это вызывается с:

copy_ptrs(target3, source, source + 5); 

Вы должны проверять, что source меньше end:

void copy_ptrs(double *target, const double *source, double *end) 
{ 
    for (; source < end; ++target, ++source) 
    *target = *source; 
} 

Итак, вы копируете indetermina т. е. количества данных вокруг места в оригинале, выталкивая за пределы массивов. Многое зависит от того, как массивы выкладываются компилятором. Похоже, вам (un) повезло, что target3 выложено по адресу ниже source, поэтому приращение target довольно часто достигает end, прежде чем перезаписать что-то критическое и аварийное.

+0

Спасибо! Вот и все. –

+0

Кроме того, знаете ли вы, как моя ошибка повлияла на предыдущие функции, хотя она должна была быть выполнена впоследствии? –

+0

Поскольку все виды данных копировались от добра, он знает, где над другими целевыми массивами. Скорее всего, вы копировали данные 10 двойных данных после 'source' над' target1' и 'target2' перед изменением' source', а затем останавливались. –