I'm learning C and I decided to make a text game as my learning project. So I'm trying this primitive "parser" that reads a text file into a 2D array, but there's a problem: this map doesn't use 1 character-wide cells, it uses 2 character-wide cells. For instance, the player is represented with a **, a door is represented like ## and so on.
That means, I need to read 2 characters of the text file and then assign it to the respective cell in the map.
Well, I made a test file that contains
aabbccddee
ffgghhiijj
kkllmmnnoo
ppqqrrsstt
uuvvwwxxyy
And I tried to read it with
#include <stdio.h>
#define ROWS 5
#define COLS 5
int main() {
FILE *mapfile = fopen("durr", "r");
char charbuffer[3], row, col, *map[ROWS][COLS];
/* Initializing array */
for (row = 0; row < ROWS; row++) {
for (col = 0; col < COLS; col++) {
map[row][col] = " ";
}
}
/* Reading file into array */
for (row = 0; row < ROWS; row++) {
for (col = 0; col < COLS; col++) {
map[row][col] = fgets(charbuffer, 3, mapfile);
}
}
/* Printing array */
for (row = 0; row < ROWS; row++) {
for (col = 0; col < COLS; col++) {
printf("%s", map[row][col]);
}
printf("\n");
}
fclose(mapfile);
return 0;
}
But when I execute it, I get this
uuuuuuuuuu
uuuuuuuuuu
uuuuuuuuuu
uuuuuuuuuu
uuuuuuuuuu
I think it has something to do with the fact that fgets return a pointer, but I'm not sure. I tried doing it with fgetc but it looks messy and I dropped it after reading about gets.
You should have strdup'ed the contents read from the file. Replace the file reading block with this:
/* Reading file into array */
for (row = 0; row < ROWS; row++) {
for (col = 0; col < COLS; col++) {
if (fgets(charbuffer, 3, mapfile))
map[row][col] = strdup(charbuffer);
}
}
and don't forget to put this at the beginning of your code too:
#include <string.h>
The main problem is that
char *map[ROWS][COLS];
only allocates space for ROWS x COLS char pointers, it does not allocate space for the strings themselves. So you're continually overwriting charbuffer as you've done it with every iteration, which explains why you end up with the same characters repeated over and over when you read out. You need to dynamically allocate the memory you need, along the lines of
for (row = 0; row < ROWS; row++) {
for (col = 0; col < COLS; col++) {
charbuffer = (char*)malloc(sizeof(char) * 3); //****
map[row][col] = fgets(charbuffer, 3, mapfile);
}
}
Related
I'm coding a small game and i decided to load a map from the file but I'm facing a problem.The file looks like this :
and i need to print it like it is in the file expect of dots. They has to be spaces.
my code for print looks like this :
void printmap(){
clear();
refresh();
FILE *mapfile;
int width=30;
int height=20;
char map[20][30];
mapfile = fopen(mapname, "r+");
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
mvprintw(0,0," ");
mvprintw(0,0,"%d %d",row,col);
refresh();
map[row][col]=fgetc(mapfile);
}
}
fclose(mapfile);
offsetW=(xMax-width)/2;
offsetY=((yMax-height)/2)-3;
printOffsetW = offsetW+23;
printOffsetY = offsetY+17;
for(int i=0;i<20;i++){
offsetW=(xMax-width)/2;
for(int y=0;y<width;y++){
if(map[i][y]=='#'){
attron(COLOR_PAIR(1));
mvprintw(i,y,"#");
attroff(COLOR_PAIR(1));
}
else if(map[i][y]=='*'){
attron(COLOR_PAIR(2));
mvprintw(i,y,"*");
attroff(COLOR_PAIR(2));
}
else if(map[i][y]==' '||map[i][y]=='.'){
mvprintw(i,y," ");
}
offsetW++;
}
offsetY++;
}
mvprintw(printOffsetY,printOffsetW,"#");
refresh();
}
Offsets are there just for centering the map (in the future), so you can ignore them.
My actual print looks like this :
And I can't really tell, where the problem is.
I would appreciate any help.
THANK YOU
As the map file includes newline character at the end of lines,
each line contains width + 1 characters. Then the sequential fgetc()
reads extra byte for each line and causes the skew in the vertical alignment.
A workaround will be to explicitly read the newline character such as:
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
...
map[row][col]=fgetc(mapfile);
}
fgetc(mapfile); // read the newline character and discard
}
Or more portable way:
char map[20][30];
char buf[BUFSIZ]; // line buffer
mapfile = fopen(mapname, "r+");
for (int row = 0; row < height; row++) {
fgets(buf, BUFSIZ, mapfile); // read each line
for (int col = 0; col < width; col++) {
...
map[row][col]=buf[col]; // assign column values of the line
}
}
When creating a 2D array and setting the value of some element, other elements get set too, what could be the reason behind such anomaly?
Following is the code example.
#include <stdio.h>
#define MAX_X 240
#define MAX_Y 2
char grid[MAX_X][MAX_Y];
int main()
{
int i,j,row,col;
col = MAX_X;
row = MAX_Y;
// Init 2D array
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
grid[i][j] = '.';
}
}
grid[0][121] = 'X'; // << [ISSUE HERE] `X` is written into 2 elements instead of 1
// Display 2D array
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
printf("%c", grid[i][j]);
}
printf("\n");
}
}
Note:
Issue showed up on g++, and was reproduced using this snippet on online gdb's compiler
You define grid as grid[240][2] which means 240 rows x 2 columns, and as #wildplasser mention you swap the col and row assignment. It should be:
row = MAX_X;
col = MAX_Y;
Im trying to make a function that sets the values of a 2D array, and then another function that prints those values.
For some reason, with my current implementation, if I create a 3x3 matrix and I set every value to the number 5, it prints the values, but it prints them counting up from 5, so it prints 567, 678, 789, when instead I want it to print the exact value that I set.
Here are the function definitions - what am I doing wrong?:
Struct Definition:
struct matrix{
char matrixName[50];
int rows;
int columns;
float* data;
};
typedef struct matrix matrix_t;
Matrix Creation:
int create_matrix(matrix_t* matrixP, int matrixLocation){
char tempName[50];
int rows, cols;
printf("Enter a name for your matrix>\n");
scanf("%s", tempName);
printf("Enter the number of rows>\n");
scanf("%d", &rows);
printf("Enter the number of cols>\n");
scanf("%d", &cols);
float * our_matrix = (float *) malloc(rows * cols * sizeof(float));
strcpy(matrixP[matrixLocation].matrixName, tempName);
matrixP[matrixLocation].rows = rows;
matrixP[matrixLocation].columns = cols;
matrixP[matrixLocation].data = our_matrix;
return 0;
}
Set Values:
int setValues(matrix_t* our_matrix, int matrix_index) {
int counter = 0;
int row = 0, col = 0;
for (col = 1; col <= our_matrix[matrix_index].columns; col++) {
for (row = 1; row <= our_matrix[matrix_index].rows; row++) {
counter++;
printf("Enter the value for column number %d of row number %d>\n", col, row);
scanf("%f", our_matrix[matrix_index].data+(col-1)+(row-1));
}
/* separate rows by newlines */
}
return 0;
}
Print:
int printMatrix(matrix_t* our_matrix, int index) {
int row = 0, col = 0;
for (col = 1; col <= our_matrix[index].columns; col++) {
for (row = 1; row <= our_matrix[index].rows; row++) {
printf(" %2.f ", *our_matrix[index].data+(col-1)+(row-1));
}
printf("\n");
}
return 0;
}
If I call the printMatrix() function without first using setValues, it seems to print the relative position of the cell that it's printing like so:
But when I call setValues() and set all values to the number 5, its prints counting up from the number 5 like this:
Your position calculation is incorrect. There's one problem and one 'aconventional notation' issue.
The problem is the calculation of the array subscripts:
scanf("%f", our_matrix[matrix_index].data+(col-1)+(row-1));
printf(" %2.f ", *our_matrix[index].data+(col-1)+(row-1));
You need to multiply the (row - 1) value by our_matrix[matrix_index].cols. You will probably do better with some shorter names for the values:
int max_col = our_matrix[matrix_index].columns;
int max_row = our_matrix[matrix_index].rows;
float *data = our_matrix[matrix_index].data;
for (col = 1; col <= max_col; col++)
{
for (row = 1; row <= max_row; row++)
{
printf("Enter the value for column number %d of row number %d>\n", col, row);
if (scanf("%f", data + (col-1) + (row-1) * max_col) != 1)
{
…report error and do not continue…
}
}
}
for (col = 1; col <= max_col; col++)
{
for (row = 1; row <= max_row; row++)
printf(" %.2f", data[(col-1) + (row-1) * max_col]);
putchar('\n');
}
That deals with the substantive bug. Note the error checking on scanf(). That is important in 'real world' programs (even if you get away without it in classes or in online contests). You could sensibly use the notation &data[(col-1) + (row-1) * max_cols] in place of data + (col-1) + (row-1) * max_cols in the call to scanf() too — that would improve the consistency of the code.
The 'aconventional notation' issue is that in C, array indexing starts at 0, not 1, and you could avoid the multitude of -1 terms by following the C conventions. This snippet also declares the loop variables when they're needed, minimizing their scope. This is a feature of C since C99 — it may not be available to you on some retrograde (but popular and widespread) platforms.
for (int col = 0; col < max_col; col++)
{
for (int row = 0; row < max_row; row++)
printf(" %.2f", data[col + row * max_col]);
putchar('\n');
}
I have this code and have no idea why my output is incorrect. I'm used to C++ not C.
Run using: ./sudoku.o < inputfile
int row = 8;
int col = 8;
int puzzle[row][col];
for (int r = 0; r < row; r++){
for (int c = 0; c < col; c++){
scanf("%d", &puzzle[r][c]);
}
}
for (int r = 0; r < row; r++){
for (int c = 0; c < col; c++){
printf("%d", puzzle[r][c]);
}
printf("\n");
}
this is my input
827154396
965327148
341689752
593468271
472513689
618972435
786235914
154796823
239841567
and this is the output I'm getting
-132765-84896035232594-208491627232765-208491623232765
00-84896120832594-84897084832594-85115713632594
10-848970848325941000
10-8489612083259400-208491648032765
1700966438000-84896035232594-208491641632765
-20846176001-208491643232765-163754450041951850
-1000-85506816832594-84897220032594
0000-20849160083276500
As noted in the comments, you should check that scanf() is successful (in this context, returns 1), and you need to make sure it reads only single digits with "%1d". Like this:
#include <stdio.h>
int main(void)
{
int row = 8;
int col = 8;
int puzzle[row][col];
for (int r = 0; r < row; r++)
{
for (int c = 0; c < col; c++)
{
if (scanf("%1d", &puzzle[r][c]) != 1)
{
fprintf(stderr, "Failed to read puzzle[%d][%d]\n", r, c);
return 1;
}
}
}
for (int r = 0; r < row; r++)
{
for (int c = 0; c < col; c++)
{
printf("%d", puzzle[r][c]);
}
printf("\n");
}
return 0;
}
With your data file, the output is (surprise, surprise):
82715439
69653271
48341689
75259346
82714725
13689618
97243578
62359141
"Ah", you said, "I wanted 9 numbers per line". But your code doesn't say that; you set row and col to 8, so you only read 8 numbers per row of the matrix, and only 8 rows. And the ninth number on the first row of date becomes the first number on the second row of your matrix, etc.
Change the limits to 9 to get the result you really wanted:
827154396
965327148
341689752
593468271
472513689
618972435
786235914
154796823
239841567
If you want line-by-line input (not necessarily a bad idea), you'd need to use fgets() (or perhaps POSIX
getline()) to read lines, and then
sscanf() to read the numbers — see How to use sscanf() in loops?
Sorry for the vague title, I wasn't really sure how to explain. I'm trying to solve the Eight Queens puzzle.
For those unfamiliar with the eight queens puzzle:
This program is supposed to find a possible way that 8 queens can
be placed on an 8x8 chessboard so that the queens cannot
capture one another -- that is, so that no column, row, or
diagonal is occupied by more than one queen.
The way I have it mapped out in my head is:
1) I'll set the whole array: chess[8][8] = {2}
2) Go to the beginning of the array, and as long as chess[i][j] == 2, it will be reassigned to 1. Then as soon as that happens, I have another program block called set_illegal, which will go and set the diagonals, row, and column to 0. (For that reason I will have to have chess[8][8] be a global variable.)
3) After set_illegal is finished, the test program will jump back into the loop of assign_q and the process will start all over again.
4) After this it will print out the solution. Unfortunately I didn't code this find multiple solutions... so it will only display 1 solution (kind of nooby programming lol...)
Any input is much appreciated!!
#include <stdio.h>
#include <stdlib.h>
#define N 8
int chess[N][N] = {2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, row1, column1;
//the reason for row1 and column1 is so that set_row, set_column, and set_diagonal
//will have a spot to start. Also I could have assigned all the elements in the array to 2 using a loop, but I was feeling a little lazy...
void assign_q(int **chess[N][N]**);
int main()
{
int row, column;
assign_q(chess);
for (row = 0; row < N; row++) //prints the whole table
{
for (column = 0; column < N; column++)
printf("%d ", chess[row][column]);
printf("\n");
}
return 0;
}
void set_illegal(void);
void assign_q(int chess[N][N])
{
int row, column;
for (column = 0; column < N; column++)
{
for (row = 0; row < N; row++)
{
if (chess[row][column] == 2) //if the element of the array is equal to 2, then it will set it to 1
{
chess[row][column] = 1;
row1 = column;
column1 = column;
set_illegal(); //goes through the column, row, and diagonal to set them all illegal
break;
}
}
}
}
void set_column(void);
void set_row(void);
void set_diagonal(void);
void set_illegal()
{
set_column();
set_row();
set_diagonal();
}
void set_column()
{
int row;
for (row = 0; row < N; row++)
chess[row][column1] = 0; //sets the column illegal
}
void set_row()
{
int column;
for (column = 0; column < N; column++)
chess[row1][column] = 0; //sets the row illegal
}
void set_diagonal()
{
int row, column;
for (row = row1 + 1, column = column1 + 1; row < N && column < N; row++, column++)
chess[row][column] = 0; //sets diagonals in the slope of -1 downwards illegal
for (row = row1 - 1, column = column1 - 1; row >= 0 && column >= 0; row--, column--)
chess[row][column] = 0; //sets diagonals in the slope of -1 upwards illegal
for (row = row1 - 1, column = column1 + 1; row >= 0 && column < N; row--, column++)
chess[row][column] = 0; //sets diagonals in the slope of +1 upwards illegal
for (row = row1 + 1, column = column1 - 1; row < N && column >= 0; row++, column--)
chess[row][column] = 0; //sets diagonals in the slope of +1 downwards illegal
}
After the change in bold, the only error I get is that the program doesnt actually work ahahaha. Anyways I'll figure that one out. Thanks for all the help!
void assign_q(int chess) - I think you want a board here, not a single field.