Ошибка множественного определения структуры, но я нигде не вижу ошибки (C ++) - PullRequest
2 голосов
/ 06 января 2020

создал структуру, скомпилировал мою программу, работал отлично, ничего не изменил, закрыл vm, перезапустил vm и vs c, а затем снова сделал make в консоли и обнаружил эту ошибку

1 warning generated.
linking build/main.o
build/Game.o:(.bss+0x60): multiple definition of `scoreArray'
build/main.o:(.bss+0x10): first defined here
clang-5.0: error: linker command failed with exit code 1 (use -v to see 
invocation)
Makefile:33: recipe for target 'build/2048' failed
make: *** [build/2048] Error 1

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

main. cpp

/**
 * File: main.cpp
 * Author: not lettin u know :)
 * Date: 20-11-2019
 * Desc:
 * Copyright: University of West of England 2017
 */
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
// include the UFCFGL301's standard library
#include <ufcfgl-30-1.h>
#include <iostream>
#include <time.h>
#include "Grid.h"
#include "Game.h"
// uncomment if you want to use the graphics library
#include <graphics.h>

using namespace std;
using namespace uwe;

/**
 * main routine, implements ...
 * @return      success
 */
int main(void) {

    srand(time(0));
    Game game;
// -------Initialising Game-------
    while(1){

        game.chooseFunction();
        grid.totalScore = 0;
        grid.initGrid();
        grid.addValue();
        cout << "\033[2J"; // this clears the terminal
        cout << "\nPlayer Score : " << grid.totalScore << "\n";
        std::cout << "\nMoves = " << grid.moves << "\n\nlast input = N/A \n";
        grid.setScore(grid.score);
        grid.drawGrid();


    // This launches graphics window where all keypresses are inputted
    // this is also where we start the lambda functions in a loop 

        initialiseGraphics(600,400);
        loop (
            [&](){
            },

            [&](keyPress keyPress){

    // w a s d are also inputted into an integer as their respective ascii value
    // so this allows the use of w a s d and also the arrow keys in controlling
    // the moves of the player

                int kpVal = keyPress.getKeyCode();

                if ( kpVal == 'q' ){
                    return true;
                }
                if ( kpVal == 'w' || kpVal == keyPress::upKey ){
                    cout << "\033[2J"; // this clears the terminal
                    grid.shiftUp();
                    cout << "Player Score : " << grid.totalScore << "\n";
                    std::cout << "\nMoves = " << grid.moves 
                              << "\n\nlast input = UP \n";
                    grid.setScore(grid.score);
                    grid.drawGrid();
                    game.checkGameState();
                    if(game.gameFinished == true){
                        return true;
                    }
                }
                if ( kpVal == 'a' || kpVal == keyPress::leftKey ){
                    cout << "\033[2J"; // this clears the terminal
                    grid.shiftLeft();
                    cout << "Player Score : " << grid.totalScore << "\n";
                    std::cout << "\nMoves = " << grid.moves  
                              << "\n\nlast input = LEFT \n";
                    grid.setScore(grid.score);
                    grid.drawGrid();
                    game.checkGameState();
                    if(game.gameFinished == true){
                        return true;
                    }
                }
                if ( kpVal == 's' || kpVal == keyPress::downKey ){
                    cout << "\033[2J"; // this clears the terminal
                    grid.shiftDown();
                    cout << "Player Score : " << grid.totalScore << "\n";
                    std::cout << "\nMoves = " << grid.moves 
                              << "\n\nlast input = DOWN \n";
                    grid.setScore(grid.score);
                    grid.drawGrid();
                    game.checkGameState();
                    if(game.gameFinished == true){
                        return true;
                    }
                }
                if ( kpVal == 'd' || kpVal == keyPress::rightKey ){
                    cout << "\033[2J"; // this clears the terminal
                    grid.shiftRight();
                    cout << "Player Score : " << grid.totalScore << "\n";
                    std::cout << "\nMoves = " << grid.moves 
                              << "\n\nlast input = RIGHT \n";
                    grid.setScore(grid.score);
                    grid.drawGrid();
                    game.checkGameState();
                    if(game.gameFinished == true){
                        return true;
                    }
                }
                return false;
            }
        );
    }
}

Game.h

#pragma once
#include <cstdio>
#include <string>
#include <graphics.h>
#include "Grid.h"

class Game{

public:

    bool canMove();
    bool checkWin();
    bool checkLoss();
    void checkGameState();
    void chooseFunction();
    void printHighScores();
    void writeHighScore();

    bool gameFinished = false;

private:

};
extern Game game;

struct highScore {
    int score;
    std::string name;
};   

Игра. cpp

#include "Grid.h"
#include "Game.h"
#include <sstream>
#include <unistd.h>
#include <iostream>
#include <cstdio>
#include <graphics.h>
#include <fstream>
#include <string>
#include <algorithm> //std::sort for array of structs sorting based on struct
                     // integer

Grid grid;
highScore scoreArray[100];

// functions to check game state for win or loss or can make moves

bool Game::canMove(){
    bool canMove = false;
    for(int x = 0; x < Grid::tilesWide; x++){
        for(int y = 0; y < Grid::tilesHigh; y++){
            if (grid.grid[x][y] == Grid::emptyCell) {
                canMove = true;
                return canMove;
            }

// multiple if statements due to if grid[3][1] was being checked with
// grid[3+1][1] then it would loop around and check against grid[1][2] 
// for an unknown reason, so to combat this i had to check specifically against
// the edge of the board 

            else if(y == 3 && x < 3){
                if( grid.grid[x][y] == grid.grid[x+1][y] ){
                    canMove = true;
                    return canMove;
                }
            }
            else if(x == 3 && y < 3){
                if( grid.grid[x][y] == grid.grid[x][y+1] ){
                    canMove = true;
                    return canMove;
                }
            }
            else if( ( x < 3 && y < 3 ) && 
                    (grid.grid[x][y] == grid.grid[x][y+1] ||
                     grid.grid[x][y] == grid.grid[x+1][y]) ) {

                canMove = true;
                return canMove;
            }
        }
    }
    return canMove;
}

bool Game::checkWin(){
    bool win = false;
    for(int x = 0; x < Grid::tilesWide; x++){
        for(int y = 0; y < Grid::tilesHigh; y++){
            if(grid.grid[x][y] == 2048){
                win = true;
                return win;
            }
        }
    }
    return win;
}

bool Game::checkLoss(){
    bool loss = false;
    if(canMove() == false ){
        loss = true;
        return loss;
    }
    return loss;
}

void Game::checkGameState(){
    if(checkWin() == true) {
        std::cout << "\n\n--------YOU WIN--------\n\n";
        gameFinished = true;
        writeHighScore();
    }
    else if(checkLoss() == true) {
        std::cout << "\n\n--------YOU LOSE--------\n\n";
        gameFinished = true;
    }
}

// functions for initializing game/options

void Game::chooseFunction(){
    while(1){
        int function = 0;
        std::cout << "\nPlease Choose A Function\n1) Play Game\n2) High Scores"
                  << "\n3) Exit Program";
        std::cout << "\nFunction : ";
        std::cin  >> function;
        if (std::cin.fail() || function < 1 || function > 3) {
            std::cin.clear();                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
            std::cin.ignore(1000,'\n'); // this is to stop the validation from
                                   // looping for each wrong character entered
            std::cout << "Not a valid option, Please re-enter \n\n" ;
            sleep(1); 

        }
        else if (function == 1) {
            std::cout << "------Launching Game------\n\n";
            std::cout << "---------LOADING---------\n";
            for(int x=0;x < 5;x++){
                std::cout << "|||||" << std::flush;
                sleep(1);
            }
            return ;
        }

        else if (function == 2) {
            std::cout << "---Printing High Scores---\n";
            std::cout << "---------LOADING---------\n";
            for(int x=0;x < 5;x++){
                std::cout << "|||||" << std::flush;
                sleep(1);
            }
            printHighScores();
            sleep(10);
        }

        else if (function == 3) {
            std::cout << "-------Now Exiting------- \n\n" << std::flush ;
            std::cout << "---------LOADING---------\n";
            for(int x=0;x < 5;x++){
                std::cout << "|||||" << std::flush;
                sleep(1);
            }
            exit(0);
        }

    }
}

// This function is called upon a win, and writes the high score ,of those who
// win the game, into a text file under the format of  SCORE - NAME

void Game::writeHighScore(){
    std::string name;
    std::cout << "\nEnter Name To Store High Score ( Max 16 Characters )\n"
              << "Name : ";
    std::getline(std::cin,name);
    // this is to stop the string being over 16 characters
    if(std::cin.fail() || name.length() > 16){
        std::cout << "\n\nPlease Enter A Max of 16 Characters\n\n";
        writeHighScore();
        return;
    }
    else{
// This opens the output stream to the high scores text file
// and immediately points to the next free line in the file
        std::ofstream HighScore;
        HighScore.open ("HighScores.txt", std::ios::app);
        HighScore << grid.totalScore << "   "<< name << std::endl; 
        HighScore.close();
        return;
    }
}

// simple comparator function to be used with std::sort in order to sort
// the array of structs containing scores and their respective player names

bool sortScore(highScore a,highScore b){
    return a.score > b.score; 
} 

// this function prints the high scores from the text file, however
// im not sure how to sort a text file each time its appended, so instead
// when this function is called, it seperates the lines of the files into
// the score and their respective player name, these are stored in a struct
// object for each line, and then the array of structs is sorted using
// std::sort and the comparator function and then the first 10 scores and names
// in the struct array are printed, TLDR, prints Top 10 scores :) 
// 
// not on the spec for the assignment but i enjoyed learning about how
// i would go about making something like this :) 

void Game::printHighScores() { // function to choose and print ascii art
    std::ifstream highScores;
    highScores.open("HighScores.txt");
    std::string line;
    int i=0;
    if(!highScores){
        std::cout << "\nCould Not Open HighScores.txt";
        sleep(2);
        return;
    }
    else{
        while(getline(highScores, line)){
            std::istringstream iss(line);
            int score;
            std::string name;

// this seperates out the score and the name string from each line in the file
            if(!(iss >> score && iss.ignore() && std::getline(iss,name))){
                break;
            }
// this adds to the array of structs defined in the header file
            scoreArray[i].score = score;
            scoreArray[i].name = name;
            i++;
        }
        std::sort(&scoreArray[0],&scoreArray[100],sortScore);
    }

// and finally... this prints the top 10 scores

    std::cout << "\n\n-------HIGH SCORES-------\n\n";
    for(int i=0; i<10; i++){
        std::cout <<i+1<<")  "<<scoreArray[i].score<<" - "<<scoreArray[i].name
        <<"\n";
    }
}

1 Ответ

4 голосов
/ 06 января 2020

Строка

highScore scoreArray[100]; 

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

Переместите это в .cpp и добавьте extern для него в заголовок.

В основном, для каждого исходного файла, который включает В этом заголовке вы объявляете переменную с именем scoreArray. Каждый .cpp, который включает этот заголовок, объявит свой собственный scoreArray. Линкер, выполняя связывание, встречает две переменные с одинаковым именем и не может решить, какая из них «правильная», поэтому он сдается и генерирует ошибку, которую вы видите.

Итак, вам нужно переместить определение в .cpp и просто ссылаться на него как extern в заголовке. (Есть несколько разных подходов к этому. Выберите тот, который подходит вам больше всего.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...