1

我定义了一个带有 int n 的结构 Board,它的值是一个小整数。在此方法被 gtk 信号“clicked”调用之前,board->n 具有正确的值。然而,当调用这个函数时,第一个 printf 语句打印出的 n 的值是一个非常大的 32665。

draw_token (GtkButton *button, cairo_t *cr, Board *board){

 printf("n: %d\n", board->n);

 printf("button clicked\n");

  //parse label of a button into the corresponding column number         
  guint col = (int)strtol(gtk_button_get_label(button), NULL, 0);

  if (make_move(board, col) == false){
    printf("draw cairo\n");
  }
}

结构:

typedef struct board Board;
struct board{
  int k;
  int n;
  char *moves;
  int player;
};

回调所在的函数:

void gui_make_buttons(GtkWidget *box, Board *board){

  guint n = board->n;
  for (int i = 1 ; i <= n ; i++){
    GtkWidget *button = gtk_button_new();
    //make label for button                                              
    char label[3];
    sprintf(label, "%d", i-1);

    gtk_button_set_label((GtkButton*)button,label);

    //    gtk_widget_show(button);                                       
    gtk_container_add(GTK_CONTAINER(box), button);
    g_signal_connect(button, "clicked",G_CALLBACK(gui_draw_token), board);
  }
}

有人可以向我解释为什么每次单击按钮时 n 的值都会更改为像 36751 这样的大值?非常感谢你

带有 main gui.c 的完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <stdbool.h>
#include "gui.h"
#include "board.h"
#include "connect.h"


gboolean draw_board (GtkWidget *widget, cairo_t *cr, gpointer board){

   guint width, height;

   width = gtk_widget_get_allocated_width (widget);
   height = gtk_widget_get_allocated_height (widget);

   guint row = height/((Board*)board)->n;
   guint col = width/((Board*)board)->n;
    printf("%d\n", row);
    printf("%d\n", col);
  //  cairo_set_source_rgb (cr, 100, 100, 255);
  //  cairo_paint (cr);

   cairo_set_source_rgb(cr, 0, 0, 255);
   for (int i = 1; i < ((Board*)board)->n ; i++){
     //draw horizontal grids;
     cairo_move_to (cr, 0, row*i);
     cairo_line_to (cr, width, row*i);
     //draw vertical grids;
     cairo_move_to (cr, col*i, 0);
     cairo_line_to (cr, col*i, height);
   }
   //   cairo_arc (cr, 100, 100, 50, 0, 2 * G_PI);

   // cairo_move_to (cr, 30, 30);
   // cairo_line_to (cr, 50, 50);
    cairo_stroke (cr);
   return false;
}


int main (int argc, char *argv[]){

    //check for correct number of arguments.                                    
  if (!check_argument(argc, argv))
    return EXIT_FAILURE;

  int k = strtol(argv[1], NULL, 0);
  int n = strtol(argv[2], NULL, 0);

  play_game(k, n);

  return EXIT_SUCCESS;
}

//show widgets and get gtk going                                       
CGUI *gui_start_gtk(Board *board){

  //assigns board to the gui struct at beginning of game
  CGUI *gui = make_gui (board);
  //  gtk_widget_queue_draw (gui->drawing_area);
// gui_draw_init_board(gui);
  gtk_widget_show_all (gui->window);
  gtk_main ();
  return gui;
}
/*
void gui_draw_init_board(GtkWidget *widget, cairo_t *cr, CGUI *gui){
  printf("HI\n");
  if (gui) {
    guint k = gui->board->k;
    guint n = gui->board->n;
    printf("%d\n", k);
  }
}
*/

void gui_make_buttons(GtkWidget *box, Board *board){

  //  guint n = board->n;
  for (int i = 1 ; i <= (board->n) ; i++){
    GtkWidget *button = gtk_button_new();
    //make label for button
    char label[3];
    //      sprintf(label, "%d", i-1);
       sprintf(label, "%d", i-1);
    gtk_button_set_label((GtkButton*)button,label); 

    //    gtk_widget_show(button);
    gtk_container_add(GTK_CONTAINER(box), button);
    g_signal_connect(button, "clicked",G_CALLBACK(gui_draw_token), board); 
  }
}

void gui_draw_token (GtkButton *button, cairo_t *cr, gpointer board){

  printf("button clicked\n");
  printf("n: %d\n", ((Board*)board)->n);
  //parse label of a button into the corresponding column number
  guint col = (int)strtol(gtk_button_get_label(button), NULL, 0);
  printf("%d\n", col);
  printf("n: %d\n", ((Board*)board)->n);
  if (make_move(board, col) == false){
    printf("draw cairo\n");
  }
}

CGUI *make_gui(Board *board){
  CGUI *gui = (CGUI*) malloc(sizeof(CGUI));
  //assign variables to gui object
  gui->board = board;
  GtkWidget *window;
  GtkWidget *frame;
  GtkWidget *drawing_area;

  gtk_init(NULL, NULL);

  //set up initial window
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "Connect-N-K");

  gtk_window_set_default_size (GTK_WINDOW(window), 600, 650);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_widget_show(window);
  g_signal_connect_swapped(G_OBJECT(window), "destroy",
               G_CALLBACK(gtk_main_quit), gui);
  //  g_signal_connect (window, "draw", G_CALLBACK (gui_draw_buttons), board);

  //create boxes to fit buttons and drawing area
  GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  GtkWidget *draw_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  GtkWidget *button_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);

  //make all buttons take up even amount of space
  gtk_box_set_homogeneous((GtkBox*)button_box, true);

  gtk_widget_set_size_request(button_box, 600, 50);

  //  gtk_box_pack_start (box, window, false, false, false);
  gtk_container_add(GTK_CONTAINER(window), box);
  gtk_container_add(GTK_CONTAINER(box), draw_box);
  gtk_container_add(GTK_CONTAINER(box), button_box);
  //set up initial frame
  frame = gtk_frame_new (NULL);
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  gtk_widget_set_size_request(frame, 600, 600);
  gtk_container_add(GTK_CONTAINER(draw_box), frame);

  //create and pack buttons.
  gui_make_buttons(button_box, board);


  //set up drawing area
  drawing_area = gtk_drawing_area_new ();
  gtk_widget_set_size_request(drawing_area, 600, 600);
  gtk_container_add (GTK_CONTAINER (frame), drawing_area);

  g_signal_connect (drawing_area, "draw", G_CALLBACK (draw_board), board);
  printf("n: %d\n", board->n);
  //  printf("board in gui: %d\n", *board);

  gui->window = window;
  gui->frame = frame;
  gui->drawing_area = drawing_area;

  /*
  //show widgets 

连接.c:

/* connect.c */


#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "gui.h"
#include "board.h"
#include "connect.h"

#define BUFFER_SIZE 10

/*
static int check_argument(int argc, char *argv[]);
static void play_game(int k, int n);
*/
/*
int main(int argc, char *argv[]){
  //check for correct number of arguments.
  if (!check_argument(argc, argv))
    return EXIT_FAILURE;

  int k = strtol(argv[1], NULL, 0);
  int n = strtol(argv[2], NULL, 0);




  play_game(k, n);
  return EXIT_SUCCESS;
}
*/

int check_argument(int argc, char *argv[]){
  if(argc < 3 || argc >3){
    fprintf(stderr, "Parameters entered incorrectly.  Input two integers for k and n respectively.\n");
    return false;
  }
  else
    return true;

}

//go through all steps of the game
void play_game(int k, int n){
  //check to see if k and n are appropriate
  if(k>n){
    fprintf(stderr, "k is greater than n, game will never be won.\n");
    return;
  }

  Board *board = make_board(k, n);
  //  print_board(board);//print initial board

  //initiate gui
  //  CGUI *gui = make_gui();//set first three vars
  //  gui_set_board(gui, board);//set the fourth var
  // CGUI *gui = gui_start_gtk(board);


  // connect_play_game_text(board);
   connect_play_game_gui(board);


  /*  int player = 1; //let first player go first
  char *s = (char*)malloc(BUFFER_SIZE);//allocate memory for int to read
  int move_result;

  do{
    fgets(s, BUFFER_SIZE, stdin);
    int cols = strtol(s, NULL, 0);
    move_result = make_move(board,cols,player);

    //switch players if legal move and no one wins 
    if(move_result == false)
      player = 3-player; 
    //do nothing is move is illegal(move_result = -1, thus letting
    //the same player choose again.
  }
  while(move_result != true);


  //free up resources
  free(s); 
  destroy_board(board);
  */
}

int connect_play_game_gui(Board *board){
  printf("n in connect: %d\n", board->n);

  CGUI *gui = gui_start_gtk(board);

  //  gui_set_board(gui, board);//set the fourth var
  //  int player = 1; //let first player go first                             
  //  char *s = (char*)malloc(BUFFER_SIZE);//allocate memory for int to read
  // int move_result;                                                           
  //  fgets(s, BUFFER_SIZE, stdin);                                           
  //  int cols = strtol(s, NULL, 0);                                          
  //  move_result = make_move(board,cols,player); 
  //switch players if legal move and no one wins                          
  //  if(move_result == false){
  //  player = 3-player;     
    return true;      
    // }

    //do nothing if move is illegal(move_result = -1, thus letting           
    //the same player choose again.                                          
    //  while(move_result != true); 

  //free up resources                                                        
    //  free(s);
    //  destroy_board(board);
}

int connect_make_move_gui(int col, Board *board, int player){
  return 1;
}

void connect_play_game_text(Board *board){
  print_board(board);//print initial board   

  char *s = (char*)malloc(BUFFER_SIZE);//allocate memory for int to read      
  int move_result;

  do{
    fgets(s, BUFFER_SIZE, stdin);
    int cols = strtol(s, NULL, 0);
    move_result = make_move(board,cols);

  }
  while(move_result != true);
  //free up resources                                                         
  free(s);
  destroy_board(board);
}

//initiate gui
//static void connect_init_gui

板.c:

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "board.h"
#define DRAW 2
#define ILLEGAL_MOVE -1


static char set_player_char(int player);
static int check_draw(Board *board);

//make a new board
Board *make_board(int k, int n){
  Board *board = (Board *) malloc(sizeof(Board));
  board->moves = (char *)malloc(n*n);
  (board->k) = k;
  (board->n) = n;
  board->player = 1;

  //make an array of empty slots based of size n^2
  for(int i = 0; i < n*n; i++){
    board->moves[i] = '.';
  }
  return board;
}

//print board with updated moves, print last row first.
void print_board(Board *board){
  int n = board->n;
  //loop through each row
  for(int i = n-1; i >= 0; i--){
    //loop through each column
    for(int j = 0; j<n; j++){
      printf("%c", (board->moves)[i*n+j]);
      printf(" ");//add space between columns
    }
    printf("\n"); //wrap around each row
  }
  printf("\n");
}

//set char for player
static char set_player_char(int player){
  char player_char;

  if (player == 1)
    player_char = 'o';
  else
    player_char = '*';

  return player_char;
}

//update board based on player's input, return the row move is made
int make_move(Board *board, int x){
  printf("inmakemove n: %d\n", board->n);
  //  printf("board in make_move: %d\n", &board);
  //if move is illegal, return
  if (!check_legal_move(board, x))
    return ILLEGAL_MOVE;

  int n = board->n;  
  int row;

  //loop through the rows of the given column to find an empty spot.
  for (int i = 0; i < n; i++){
    if ((board->moves)[i*n+x] == '.'){
      (board->moves)[i*n+x] = set_player_char(board->player);
      row = i;
      break;
    }
  }

  print_board(board);

  //Check to see if a player has won the game.;
  int stat = check_win(board, x, row);
  if (stat == true){
    fprintf(stdout, "Player %d won the game.\n", board->player);
    return true;
  }

  //if all slots are filled, game is a draw.
  if(stat == DRAW){
    fprintf(stdout, "Game was a draw.\n");
    return true;
  }

  //if no one won, game continues.
  else{
    board->player = 3-(board->player);
    return false;
  }
}

//check to see if move x is legal
int check_legal_move(Board *board, int x){
  int n = board->n;

  //see if column entered is legal.
  if (x >= (board->n) || x<0){
    fprintf(stderr, "Illegal move by player %d at column %d\
, number entered outside range of available columns.\n", board->player, x);
    return false;
  }

  //see if column entered is already filled
  if ((board->moves)[(n-1)*n+x] != '.'){
    fprintf(stderr, "Illegal move by player %d at column %d\
, column is already filled.\n", board->player, x);
    return false;
  }
  return true;
}

//check for winning move
int check_win(Board* board, int x, int row){

  int n = board->n;
  int k = board->k;
  int current_move = row*n+x; //slot that the current move fills

  char *moves = board->moves;
  char player_char = set_player_char(board->player);

  int score;
  score = 1;

  //Check to see how many continuous slots are filled with the current player'
  //s token horizontally. 
  //going right                                          
  for (int i = 1; i<k && x+i<n; i++){
    if(moves[current_move+i] == player_char)
      score ++;
    else
      break;
  }

  //going left                                                         
  for(int i = 1; i<k && x-i>=0; i++){
    if(moves[current_move-i] == player_char)
      score++;
    else
      break;
  }

  //if horizontally connect to k, the player wins.
  if (score>=k)
    return true;

 //if not, check vertical.
  score = 1;
   //going up
  for (int i = 1; i<k && row+i<n; i++){
    if(moves[current_move+n*i] == player_char)
      score ++;
    else
      break;
  }

  //going down
  for(int i = 1; i<k && row-i>=0; i++){
    if(moves[current_move-n*i] == player_char)
      score ++;
    else
      break;
  }

  //if vertically connect to k, the player wins.                    
  if (score>=k)
    return true;

  //if not, check rising to right diagnol. Reset score like previously.  
  score = 1;

  //going right and up
  for(int i = 1; i<k && row+i<n && x+i<n; i++){
    if(moves[current_move+n*i+i] == player_char)
      score ++;
    else
      break;
  }
  //going left and down
  for(int i = 1; i<k && row-i>=0 && x-i>=0; i++){
    if(moves[current_move-n*i-i] == player_char)
      score ++;
    else
      break;
  }

  //if right diagonally connect to k, the player wins.                      
  if (score>=k)
    return true;

  //if not, check left rising diagonal.
  score = 1;
  //check right and down
  for(int i = 1; i<k && x+i<n && row-i>=0; i++){
    if(moves[current_move-n*i+i] == player_char)
      score ++;
    else
      break;
  }
  //check left and up
  for(int i = 1; i<k && x-i>=0 && row+i<n; i++){
    if(moves[current_move+n*i-i] == player_char)
      score ++;
    else
      break;
  }

  //if left diagonally connect to k, the player wins.                          
  if (score>=k)
    return true;

  if(check_draw(board))
    return DRAW;

  //if no k connect is made in any direction, game is not won. 
  return false;
}

//check to see if game has come to a draw
static int check_draw(Board *board){
  int n = board->n;

  //loop through the top row to see if there are any empty slots left
  for (int i = 0; i<n; i++){
    if((board->moves)[n*(n-1)+i] == '.')
      return false;
  }
  //if no empty slots left, game was a draw.
  return true;
}

//Free up resources.
void destroy_board(Board *board){
  free(board->moves);
  free(board);
}

很抱歉,这很长而且很混乱,我仍在编写代码并且是 C 的新手。

4

3 回答 3

1

不是我知道 gtk,而是一个快速的谷歌,看起来,你在回调中得到的板实际上并不是你正在传递的板。您对 clicked 事件的回调签名不正确

它应该看起来有点像

void button_clicked(GtkWidget *widget, gpointer data)
于 2013-02-12T20:15:16.950 回答
1

您需要更改void gui_draw_token (GtkButton *button, cairo_t *cr, gpointer board)void gui_draw_token (GtkButton *button, gpointer board)

您不能只是编造回调签名并希望一切正常。对于签名,您需要查看适合信号的文档。例如在这种情况下GtkButton 点击​​信号文档。

如果您删除所有不必要的代码并注释掉代码,这也将有助于我们回答您的问题。

于 2013-02-13T08:24:51.343 回答
0

编辑:是的,不要注意这一点。我以为是在循环char label[3]初始化的,他更新了三次,导致未定义的输出和label[0]label[1]label[2]

这就是我粗略查看 739782781 行代码所得到的结果。对不起大家。


你没有告诉label哪一个要更新sprintf

char label[3];
sprintf(label, "%d", i-1);
            ^ is wrong

它应该是

char label[3];
sprintf(label[n-1], "%d", i-1);

我认为。

于 2013-02-12T20:15:35.170 回答