Good morning
This is big problem for me to link all files (main.c, myFunc.c, myFuncHeaders.h and MakeFile).
Problem is multiple definition when I don't know what should I do with it. I used global variables char board[3][3]
, char board_checked[3][3]
and int playersRound
. I know that global would be unnecessary and bad designed program, but I wanted try something new. Simple tic tac toe game
In one file(all in one), code works. Here:
#include<stdio.h>
#include <stdlib.h>
char board[3][3] = {{'_', '_', '_'},{'_', '_', '_'},{'_', '_', '_'} };
char board_checked[3][3] = {{'+', '+', '+'},{'+', '+', '+'},{'+', '+', '+'}};
int playersRound = 0;
// It shows board
void show_board(){
char * space = " ";
puts("\tPlansza\n\t==================================");
for(int i = 1; i < 4; i++)
{
printf("%s|%d|", space, i);
}
printf("\n");
for(int i = 0; i < 3; i++){
printf("\t|%d|",i+1);
for(int j = 0; j < 3; j++)
{
printf("%c %s", board[i][j], space);
}
printf("\n\n");
}
puts("\t==================================\n");
}
// This function add a player's mark - 'X' or 'O' - to board
void add_mark(int *p, int player){
// If it isn't reserved by other mark
if(board_checked[p[0]-1][p[1]-1] != '-'){
// x (p[1]) and y (p[0]) vectors are (1, 2, 3)
if(1 <= p[0] && p[0] <= 3 && 1 <= p[1] && p[1] <= 3)
{
if(player == 1)
{
// Add to board 'X'
board[p[0]-1][p[1]-1] = 'O';
// and unchecked at the same position 'board_checked'
board_checked[p[0]-1][p[1]-1] = '-';
}
else
{
// Add to board 'X'
board[p[0]-1][p[1]-1] = 'X';
// and unchecked at the same position 'board_checked'
board_checked[p[0]-1][p[1]-1] = '-';
}
// If Everything is Okey go to next playersRound
playersRound++;
}
}
else
// On start variable is position[2] = {0,0}; it's mean that I made exception
if(!(0 == p[0] && 0 == p[1]))
{
puts("Nie podales poprawnych parametrow");
sleep(2);
}
}
// This function check every position where any mark have been added
int structure_check(int player){
//return winner
for(int i = 0; i < 2; i++){
// Check horizontal
for(int level = 0; level < 3; level++)
if(board[level][0] == board[level][1] && board[level][0] == board[level][2] && board[level][0] != '_')return player;
// Check vertical
for(int level = 0; level < 3; level++)
if(board[0][level] == board[1][level] && board[0][level] == board[2][level] && board[0][level] != '_')return player;
// Check diagonal left
if(board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != '_')return player;
// Check diagonal right
if(board[2][0] == board[1][1] && board[2][0] == board[0][2] && board[0][2] != '_')return player;
}
// Draw - when no one of two players won
return 0;
}
int main(char argc, char * argv[]){
int player = 1;
int position[2] = {0,0};
int status = 0;
show_board();
while(playersRound < 10){
// Short information
if(player == 1) puts("Gracz 1:");
else puts("Gracz 2:");
// Get position
printf("\tx:"); scanf("%d", &position[0]);
printf("\ty:"); scanf("%d", &position[1]);
// status game, win or draw
status = structure_check(player);
// Players movement in playersRounds
if(playersRound%2 == 0) player = 1;
else player = 2;
// This add mark to board by player
add_mark(position, player);
// Clear console
system("cls");
// Show only board
show_board();
// To be sure it works
status = structure_check(player);
// It finish when someone won game
if(status != 0) break;
}
if(player == 1)
printf("Wygrywa gracz: 1 z 'O'");
else
printf("Wygrywa gracz: 2 z 'X'");
puts(" ||| Gratulacje! |||");
return 0;
}
Problem is here:
main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "myFunc.c"
#include "myFuncHeaders.h"
int main(char argc, char * argv[]){
int player = 1;
int position[2] = {0,0};
int status = 0;
show_board();
while(playersRound < 10){
// Short information
if(player == 1) puts("Gracz 1:");
else puts("Gracz 2:");
// Get position
printf("\tx:"); scanf("%d", &position[0]);
printf("\ty:"); scanf("%d", &position[1]);
// status game, win or draw
status = structure_check(player);
// Players movement in playersRounds
if(playersRound%2 == 0) player = 1;
else player = 2;
// This add mark to board by player
add_mark(position, player);
// Clear console
system("clear");
// Show only board
show_board();
// To be sure it works
status = structure_check(player);
// It finish when someone won game
if(status != 0) break;
}
if(player == 1)
printf("Wygrywa gracz: 1 z 'O'");
else
printf("Wygrywa gracz: 2 z 'X'");
puts(" ||| Gratulacje! |||");
return 0;
}
myFunc.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // sleep()
#include "myFuncHeaders.h"
char board[3][3] = {{'_', '_', '_'},{'_', '_', '_'},{'_', '_', '_'} };
char board_checked[3][3] = {{'+', '+', '+'},{'+', '+', '+'},{'+', '+', '+'}};
int playersRound = 0;
// It shows board
void show_board(){
char * space = " ";
puts("\tPlansza\n\t==================================");
for(int i = 1; i < 4; i++)
{
printf("%s|%d|", space, i);
}
printf("\n");
for(int i = 0; i < 3; i++){
printf("\t|%d|",i+1);
for(int j = 0; j < 3; j++)
{
printf("%c %s", board[i][j], space);
}
printf("\n\n");
}
puts("\t==================================\n");
}
// This function add a player's mark - 'X' or 'O' - to board
void add_mark(int *p, int player){
// If it isn't reserved by other mark
if(board_checked[p[0]-1][p[1]-1] != '-'){
// x (p[1]) and y (p[0]) vectors are (1, 2, 3)
if(1 <= p[0] && p[0] <= 3 && 1 <= p[1] && p[1] <= 3)
{
if(player == 1)
{
// Add to board 'X'
board[p[0]-1][p[1]-1] = 'O';
// and unchecked at the same position 'board_checked'
board_checked[p[0]-1][p[1]-1] = '-';
}
else
{
// Add to board 'X'
board[p[0]-1][p[1]-1] = 'X';
// and unchecked at the same position 'board_checked'
board_checked[p[0]-1][p[1]-1] = '-';
}
// If Everything is Okey go to next playersRound
playersRound++;
}
}
else
// On start variable is position[2] = {0,0}; it's mean that I made exception
if(!(0 == p[0] && 0 == p[1]))
{
puts("Nie podales poprawnych parametrow");
sleep(2);
}
}
// This function check every position where any mark have been added
int structure_check(int player){
//return winner
for(int i = 0; i < 2; i++){
// Check horizontal
for(int level = 0; level < 3; level++)
if(board[level][0] == board[level][1] && board[level][0] == board[level][2] && board[level][0] != '_')return player;
// Check vertical
for(int level = 0; level < 3; level++)
if(board[0][level] == board[1][level] && board[0][level] == board[2][level] && board[0][level] != '_')return player;
// Check diagonal left
if(board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != '_')return player;
// Check diagonal right
if(board[2][0] == board[1][1] && board[2][0] == board[0][2] && board[0][2] != '_')return player;
}
// Draw - when no one of two players won
return 0;
}
myFuncHeaders.h
void show_board();
// This function add a player's mark - 'X' or 'O' - to board
void add_mark(int *p, int player);
// This function check every position where any mark have been added
int structure_check(int player);
MakeFile
main: main.o myFunc.o
gcc -o main main.o myFunc.o
myFunc.o: myFunc.c myFunc.o
gcc -c -o myFunc.o myFunc.c
Output:
*my foleder*
~/zadania_domowe/kolko_krzyzyk $ make
cc -c -o main.o main.c
make: circular version myFunc.o <- myFunc.o lost.
gcc -c -o myFunc.o myFunc.c
gcc -o main main.o myFunc.o
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o:(.data+0x0): multiple definition of `board'; main.o:(.data+0x0): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o:(.data+0x10): multiple definition of `board_checked'; main.o:(.data+0x10): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o:(.bss+0x0): multiple definition of `playersRound'; main.o:(.bss+0x0): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o: in function `show_board':
myFunc.c:(.text+0x0): multiple definition of `show_board'; main.o:main.c:(.text+0x0): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o: in function `add_mark':
myFunc.c:(.text+0xf5): multiple definition of `add_mark'; main.o:main.c:(.text+0xf5): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: myFunc.o: in function `structure_check':
myFunc.c:(.text+0x2a6): multiple definition of `structure_check'; main.o:main.c:(.text+0x2a6): first defined here
collect2: error: ld returned 1 exit status
make: *** [makefile:2: main] Error 1
I try with extern
global, put this globals into the main()
and then send to the functions. I had more errors then I expected. If someone have link or source to the same problem I will be glad for this information.
The problem is that you #include "myFunc.c"
in main.c
so you include the implementations of functions show_board
, add_mark
, etc. in the main.o
compiled object, and those functions are also included in the myFunc.o
compiled object, result of compiling the same source file directly. The linker, on seeing this, complaints, as it cannot know which function to use, and when you make a call to e.g. add_mark
in main
it doesn't know which one is to be called.
To solve your problem, you just need to take off the line
#include "myFunc.c"
and include also myFuncHeaders.h
in the file myFunc.h
, so you can check that the definitions given in the header file are compatible with the implementations you provide in the file myFunc.c
.
There is also an error from make
telling that you have included a rule indicating that myFunc.o
file depends on myFunc.o
which is a circular dependence, and it is an error (make cannot be given dependency rules with loops, as it would never end if it had to allow them) you need to change
myFunc.o: myFunc.c myFunc.o
gcc -c -o myFunc.o myFunc.c
into
myFunc.o: myFunc.c myFuncHeaders.h
gcc -c -o myFunc.o myFunc.c
and write a similar one for main.o
(which has been taken by default with the internal make's version, you will see that make has called cc
compiler, to compile main.c
instead of gcc
)
main.o: main.c myFuncHeaders.h
gcc -c -o main.o main.c
The rule is to think that if you touch (edit) any of the files main.c
or myFuncHeaders.h
(this last because you have modified the interface to the functions defined in myFunc.c
, then you need to create a new compilation of main.c
to main.o
, or the final executable will be inconsistent (and your program will crash).