Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 06.04.2014, 16:32   #1
andrey_snegovik
 
Регистрация: 06.04.2014
Сообщений: 7
Восклицание Ошибка: multiple definition of ...

Добрый день! Не получается скомпилировать программу, хотя вроде все переменные и функции объявлены правильно. Подскажите пожалуйста!

Программа состоит из четырёх файлов. Всё основное выполнение происходит в main.cpp, остальное - модули.

primer.cpp
Код:
#include <iostream>
using namespace std;

void Move_Disks (int nn, char sourse, char dest, char tmp){
if (nn==1) {
    cout <<"Perestavit disk 1 so stolbika "<< sourse <<" na stolbik " << dest <<endl;
}
else {
    Move_Disks (nn-1, sourse, tmp, dest);
    cout <<"Perestavit disk "<< nn <<"so stolbika " <<sourse <<" na stolbik " <<dest<<endl;
    Move_Disks (nn-1, tmp, dest, sourse);
}
}
procedure.cpp
Код:
#include <iostream>
using namespace std;

#define N 3
#define M N

void input_array (int A[N][M]) {
for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++) {
cout << "Enter [" << i + 1 << ";" << j + 1 << "]:" << endl;
cin >> A[i][j];
}
}

void print_array (int A[N][M]) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
cout << A[i][j] << " ";
}
cout << endl;
}
}

// Процедура, обрабатывающая одномерный массив
int proc (int T[]) {
int sum = 0;
for (int i = 0; i < N; i++) {
sum += T[i];
}
return sum;
}

int proc1 (int T1[]) {
int sum1 = 0;
for (int i = 0 ; i < N ; i++) {
sum1 += T1[i];
}
return sum1;}
main.cpp
Код:
#include <iostream>
#include "procedure.cpp"
#include "primer.cpp"

using namespace std;

int main () {
//Выполнение второй программы
cout <<endl;
cout << "*******************"<<endl;
cout <<  "Программа с процедурой" <<endl;
cout << "*******************"<<endl;

cout << "Fill array" << endl;
int B[N][M];
// Заполняем массив
input_array(B);
// Выводим массив на экран
print_array(B);

// Обрабатываем двумерный массив
// Смотрим сначала главную диагональ "вырезаем" ее из двумерного массива

int GDIAG[N] = {0};
for (int i = 0; i < N ; i++)
{
GDIAG[i] = B[i][i];
}
int gSum = proc(GDIAG); // Сумма элементов на главной диагонали
// Смотрим побочную диагональ
int PDIAG[N] = {0};
for (int i = M - 1 ; i >= 0 ; i--)
{
PDIAG[i] = B[i][i];
}
int pSum = proc1(PDIAG); // Сумма элементов на побочной диагонали

cout << "Glavnaya diagonal : " << gSum << " ; Pobochnaya diagonal: " << pSum << endl;

if (gSum > pSum)
{
cout << "Glavnaya diagonal bol'she! " << endl;

}
else
if (gSum == pSum)
{
cout << "Odinakovo!!" << endl;
}
else {
cout << "Pobochnaya bol'she!!" << endl;
}
    //Конец выполнения второй программы

    //Выполнение второй программы
cout << "*******************************"<<endl;
cout <<  "Программа из методички" <<endl;
cout << "*******************************"<<endl;
int P;
cout << "Vvedite chislo disks:";
cin>> P;
Move_Disks (P, 'A', 'C','B');
    //Конец выполнения второй программы

}
Выдаёт 4 ошибки:
Цитата:
In function `Z10Move_Disksiccc'
multiple definition of `Move_Disks(int, char, char, char)'
first defined here
collect2.exe:-1: ошибка: error: ld returned 1 exit status
Не понимаю, в чем проблема? Подскажите пожалуйста!
andrey_snegovik вне форума Ответить с цитированием
Старый 06.04.2014, 18:51   #2
casekey
Пользователь
 
Регистрация: 03.11.2010
Сообщений: 95
По умолчанию

во-первых, раскидай декларацию функций в заголовочные файлы и подключай их, а не напрямую cpp - это неправильно.

Например:
Файл Primer.h
Код:
#pragma once
#include <iostream>
using namespace std;

void Move_Disks (int, char, char, char); // Здесь мы объявляем функцию Move_Disks, но не определяем ее
Файл primer.cpp:
Код:
#include "primer.h"

void Move_Disks (int nn, char sourse, char dest, char tmp){
  if (nn==1) {
    cout <<"Perestavit disk 1 so stolbika "<< sourse <<" na stolbik " << dest <<endl;
  }
  else {
    Move_Disks (nn-1, sourse, tmp, dest);
    cout <<"Perestavit disk "<< nn <<"so stolbika " <<sourse <<" na stolbik <<dest<<endl;
    Move_Disks (nn-1, tmp, dest, sourse);
  }
}
А в main.cpp подключаете primer.h и вызываете Move_Disks. Аналогично надо сделать с procedure.cpp, разделив его на файл-заголовка и файл-реализации

Последний раз редактировалось casekey; 06.04.2014 в 19:05.
casekey вне форума Ответить с цитированием
Старый 06.04.2014, 20:52   #3
andrey_snegovik
 
Регистрация: 06.04.2014
Сообщений: 7
По умолчанию

casekey, спасибо Вам добрый человек большое!) Ваш способ помог!
А если не секрет, в чём разница, как подключать, через .cpp или через .h? И почему через .cpp не работает?
Только сейчас начинаем c++ изучать в универе всех тонкостей не знаю...

Кстати, если отдельно запускать программу с функцией Move_Disks, то работает без определения. Вот код:
Код:
#include <iostream>
using namespace std;

void Move_Disks (int n, char sourse, char dest, char tmp){
if (n==1)
{cout <<"Perestavit disk 1 so stolbika"<< sourse <<"na stolbik" << dest <<endl;}
else {Move_Disks (n-1, sourse, tmp, dest);
cout <<"Perestavit disk"<< n <<"so stolbika" <<sourse <<"na stolbik" <<dest<<endl;
Move_Disks (n-1, tmp, dest, sourse);}}

int main ()
{int N;
cout << "Vvedite chislo disks:";
cin>> N;
Move_Disks (N, 'A', 'C','B');

return 0;
}
И ещё один момент. Файл-заголовок - это primer.h? А файл-реализации - это где у меня программа выполняется основная, так?)

Последний раз редактировалось andrey_snegovik; 06.04.2014 в 21:00.
andrey_snegovik вне форума Ответить с цитированием
Старый 06.04.2014, 21:20   #4
casekey
Пользователь
 
Регистрация: 03.11.2010
Сообщений: 95
По умолчанию

Цитата:
А если не секрет, в чём разница, как подключать, через .cpp или через .h? И почему через .cpp не работает?
Цитата:
И ещё один момент. Файл-заголовок - это primer.h? А файл-реализации - это где у меня программа выполняется основная, так?)
В общем случае .h - это файл, где мы определяем имена, ф-ии, классы, но не указываем как они реализованы, их реализацию осуществляется в файле .cpp

К примеру, можете проверить такой код:
Код:
int a();
int a();
int a();
т.к эти ф-ии не имеют тела (т.е это только их определение, их может быть сколь угодно) - это компилируется
другое дело, если бы было так:
Код:
int a(){}
int a(){}
Вот тут уже будет ошибка.

Еще прочитайте про директиву include и что конкретно она делает с файлом при компиляции. В вашем примере функция Move_disks попала и в файл main.cpp и в файл primer.cpp. Линкер и сообщил что при линковке нашел две функции с определением.

Прочитайте так же про эту директиву
Код:
#pragma once
...
хотя лучше было бы написать так:
Код:
#ifndef PRIMER_H
#define PRIMER_H
...
#endif

Последний раз редактировалось casekey; 06.04.2014 в 21:26.
casekey вне форума Ответить с цитированием
Старый 06.04.2014, 21:51   #5
andrey_snegovik
 
Регистрация: 06.04.2014
Сообщений: 7
По умолчанию

В принципе всё понятно, кроме одного момента.
Цитата:
Еще прочитайте про директиву include и что конкретно она делает с файлом при компиляции. В вашем примере функция Move_disks попала и в файл main.cpp и в файл primer.cpp. Линкер и сообщил что при линковке нашел две функции с определением.
Ведь в main.cpp я только вызываю функцию уже со значениями
Код:
Move_Disks (P, 'A', 'C','B');
Почему тогда получается две функции с определением? Если я вроде как определяю её только в primer.cpp?
andrey_snegovik вне форума Ответить с цитированием
Старый 06.04.2014, 23:26   #6
casekey
Пользователь
 
Регистрация: 03.11.2010
Сообщений: 95
По умолчанию

Я же говорю посмотри как работает include. Include подставил содержимое файла primer.cpp в мейн перед компиляцией после чего скомпилировал обьектный файл скажем main.o. аналогично скомпилировался primer.cop в primer.o. После чего линкер пытаеться слинковать эти два файла и видит что в обоих есть функции с одинаковыми именами и обе имеют тело
casekey вне форума Ответить с цитированием
Старый 10.04.2014, 17:08   #7
andrey_snegovik
 
Регистрация: 06.04.2014
Сообщений: 7
По умолчанию

casekey, ещё раз к Вам обращусь. Проблема в том, что мне в основную программу (main.cpp) нужно включать модули через заголовочные файлы.
Пример:

Код:
#include <iostream>
#include "recursion.h"
#include "massiv.h"
int main () {
}
Но дело в том, что у меня в модуле massiv.cpp имеются глобальные переменные:
Код:
const int L=7, M=7;
int p, k, o;
И собственно при компиляции выдаёт ошибку. Вот скриншот: prntscr.com/38osxd

Как теперь эти переменные перенести? На всякий случай прикладываю текущую структуру программы.
lab_8.zip

Заранее спасибо, очень выручаете!

Последний раз редактировалось andrey_snegovik; 10.04.2014 в 18:17.
andrey_snegovik вне форума Ответить с цитированием
Старый 10.04.2014, 17:38   #8
ROD
Linux C++ Qt ARM
Старожил
 
Аватар для ROD
 
Регистрация: 30.11.2008
Сообщений: 3,030
По умолчанию

Во-первых перенести глобальные переменные в .h файл.
Во-вторых не использовать глобальные переменные (если без них можно обойтись).
В-третьих глобальные константы можно задефайнить или заменить на перечисления. (в .h файле, причем если они реально глобальные то я бы их вынес вообще в отдельный .h файл).

К стати, у меня компилятор ни на что не ругается. (Компилятор mingw32, IDE QtCreator 3.0.82)

upd.

И самое главное забыл - защитить .h файлы от повторного включения (include guard), как уже писалось выше.
(и, по возможности, не используйте #pragma once - не все компиляторы это понимают, да и не обязаны они эту директиву понимать)
Дилетант широкого профиля.

"Слова ничего не стоят - покажите мне код!" © Линус Торвальдс

Последний раз редактировалось ROD; 10.04.2014 в 17:46.
ROD вне форума Ответить с цитированием
Старый 10.04.2014, 17:51   #9
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Цитата:
Сообщение от ROD Посмотреть сообщение
Во-первых перенести глобальные переменные в .h файл.
ток не забыть extern сделать, а в cpp оставить.

Цитата:
Сообщение от ROD Посмотреть сообщение
(и, по возможности, не используйте #pragma once - не все компиляторы это понимают, да и не обязаны они эту директиву понимать)
я обычно юзаю и то и то, и пока не видел компиля чтоб не понимал.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 10.04.2014, 18:02   #10
ROD
Linux C++ Qt ARM
Старожил
 
Аватар для ROD
 
Регистрация: 30.11.2008
Сообщений: 3,030
По умолчанию

Цитата:
Сообщение от Пепел Феникса Посмотреть сообщение
я обычно юзаю и то и то, и пока не видел компиля чтоб не понимал.
keil uVision не понимает (правда, кажется, он вообще include guard как-то не очень понимает, по крайней мере то, что работает в gcc, в кейле не компилируется)
Дилетант широкого профиля.

"Слова ничего не стоят - покажите мне код!" © Линус Торвальдс
ROD вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
C++ : multiple definition of main AnryFlame Помощь студентам 2 16.10.2012 18:00
Ошибка error C2374: 'n' : redefinition; multiple initialization inmanika Помощь студентам 5 13.12.2011 01:22
Ошибка: "Multiple-step operation generated errors. Check each status value" artemavd Общие вопросы Delphi 4 23.10.2011 08:07
multiple definition jojahti Общие вопросы C/C++ 9 20.08.2009 16:54
Qbasic ошибка "duplicate definition" Костя КС Помощь студентам 5 26.05.2009 22:23