#Take a 2 dimensional string in a txt file
146 messages · Page 1 of 1 (latest)
When your question is answered use !solved to mark the question as resolved.
Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.
here is the code
!code
```c
int main() {}
```
int main() {}
Also what is a "2 dimensional string"?
that's not legal C
I got this error
(0, 0) : Ç.
(0, 1) : ü.
(0, 2) : é.
(0, 3) : â.
(0, 4) : ä.
(0, 5) : à.
(0, 6) : å.
(0, 7) : ç.
(0, 8) : ê.
(0, 9) : ë.
(0, 10) : è.
(0, 11) : ï.
(0, 12) : î.
(0, 13) : ì.
(0, 14) : Ä.
(0, 15) : Å.
(0, 16) : É.
(1, 0) : Ç.
(1, 1) : ü.
(1, 2) : é.
(1, 3) : â.
(1, 4) : ä.
(1, 5) : à.
(1, 6) : å.
(1, 7) : ç.
(1, 8) : ê.
(1, 9) : ë.
(1, 10) : è.
(1, 11) : ï.
(1, 12) : î.
(1, 13) : ì.
(1, 14) : Ä.
(1, 15) : Å.
(1, 16) : É.
(2, 0) : Ç.
(2, 1) : ü.
(2, 2) : é.
(2, 3) : â.
(2, 4) : ä.
(2, 5) : à.
(2, 6) : å.
(2, 7) : ç.
(2, 8) : ê.
(2, 9) : ë.
(2, 10) : è.
(2, 11) : ï.
(2, 12) : î.
(2, 13) : ì.
(2, 14) : Ä.
(2, 15) : Å.
(2, 16) : É.
(3, 0) : Ç.
(3, 1) : ü.
(3, 2) : é.
(3, 3) : â.
(3, 4) : ä.
(3, 5) : à.
(3, 6) : å.
(3, 7) : ç.
(3, 8) : ê.
(3, 9) : ë.
(3, 10) : è.
(3, 11) : ï.
(3, 12) : î.
(3, 13) : ì.
(3, 14) : Ä.
(3, 15) : Å.
(3, 16) : É.
(4, 0) : Ç.
(4, 1) : ü.
(4, 2) : é.
(4, 3) : â.
(4, 4) : ä.
(4, 5) : à.
(4, 6) : å.
(4, 7) : ç.
(4, 8) : ê.
(4, 9) : ë.
(4, 10) : è.
(4, 11) : ï.
(4, 12) : î.
(4, 13) : ì.
(4, 14) : Ä.
(4, 15) : Å.
(4, 16) : É.
(5, 0) : Ç.
(5, 1) : ü.
(5, 2) : é.
(5, 3) : â.
(5, 4) : ä.
(5, 5) : à.
(5, 6) : å.
(5, 7) : ç.
(5, 8) : ê.
(5, 9) : ë.
(5, 10) : è.
(5, 11) : ï.
(5, 12) : î.
(5, 13) : ì.
(5, 14) : Ä.
(5, 15) : Å.
(5, 16) : É.
(6, 0) : Ç.
(6, 1) : ü.
(6, 2) : é.
(6, 3) : â.
(6, 4) : ä.
(6, 5) : à.
(6, 6) : å.
(6, 7) : ç.
(6, 8) : ê.
(6, 9) : ë.
(6, 10) : è.
(6, 11) : ï.
(6, 12) : î.
(6, 13) : ì.
Why ?
;compile
map[][]
<source>: In function 'main':
<source>:3:1: error: 'map' undeclared (first use in this function)
3 | map[][]
| ^~~
<source>:3:1: note: each undeclared identifier is reported only once for each function it appears in
<source>:3:5: error: expected expression before ']' token
3 | map[][]
| ^
Build failed
!vla
A Variable Length Array (VLA) is an array where the size is not constant and depends on a variable.
int size = rand();
int vla[size]; // VLA of type int[size]
int not_vla[10]; // regular array of type int[10]
constexpr int size = 10;
int arr[size]; // also not a VLA, of type int[10]
VLAs have poor compiler support and can lead to unsafe code. The core issue with VLAs is that the compiler doesn't know the size of the stack frame. Without warning flags like -Wvla, it can be easy to create a VLA by accident, even in C++ with some compilers.
:white_check_mark: available since C99
:no_entry: not available in C++ at all
:no_entry: was never supported by MSVC
:warning: optional feature since C11
:warning: supported as non-standard extension by GCC, clang
ok but it’s for a school project don’t know how to print a board game differently
I got this in my txt file
```c
int main() {}
```
int main() {}
Cause that is most certainly not what your output looks like
2 17
1 9 1 @ 0 0 0
2 9 14 @ 16 0 0
- - - - -B- - - -
- - - - -B- - - -
- - - - - - - - -
- - - -B- - - - -
- - - -B- - - - -
- - - - - - - - -
- - - - - - - - -
- - - - - - - - -
- - - - - - - - -
Okay. I still don't understand what the printing has to do with the VLA
I mean, just do this instead:
#define NbCol 17
...
char map[NbCol][NbCol];
It’s because I got this error
(9, 3) : â.
(9, 4) : ä.
(9, 5) : à.
(9, 6) : å.
(9, 7) : ç.
(9, 8) : ê.
(9, 9) : ë.
(9, 10) : è.
(9, 11) : ï.
(9, 12) : î.
(9, 13) : ì.
(9, 14) : Ä.
(9, 15) : Å.
(9, 16) : É.
(10, 0) : Ç.
Error reading map data at position (10, 0) : Ç.
!f
int loadGame(int* nbPlayers,
struct Player P[],
int* NbCol,
char map[*NbCol][*NbCol]) {
FILE* file = fopen("..//last_party.txt", "r");
if (file == NULL) {
printf("No saved game found.\n");
return 0;
}
if (fscanf(file, "%d %d", nbPlayers, NbCol) != 2) {
printf("Error reading number of players and number of columns.\n");
fclose(file);
return 0;
}
printf("nb col %d\n\n", *nbPlayers);
for (int i = 0; i < *nbPlayers; i++) {
P[i].name = malloc(30 * sizeof(char));
if (fscanf(file, "%s %d %d %c %d %d %d", P[i].name, &P[i].nbBarriere,
&P[i].color, &P[i].pawn, &P[i].posX, &P[i].posY,
&P[i].score) != 7) {
printf("Error reading player data.\n");
fclose(file);
return 0;
}
}
for (int i = 0; i < *NbCol; i++) {
for (int j = 0; j < *NbCol; j++) {
printf("(%d, %d) : %c.\n", i, j, &map[i][j]);
if (fscanf(file, "%c", &map[i][j]) != 1) {
printf("Error reading map data at position (%d, %d) : %c.\n", i, j,
&map[i][j]);
fclose(file);
return 0;
}
}
fscanf(file, "\n");
}
fclose(file);
return 1;
}
The problem is that the saveGame function return an error with the "Error reading map data "
and I don’t understand where the error are
What do you do there?
For example this line:
printf("(%d, %d) : %c.\n", i, j, &map[i][j]);
```What is it supposed to do?
I put this to see what I have of map from which coordinates to debug
I would truly recommend you to compile with -Wall -Wextra
This is the problem since instead of space and "-" I got
(9, 7) : ç.
(9, 8) : ê.
(9, 9) : ë.
(9, 10) : è.
(9, 11) : ï.
letters
with accents that have nothing to do with my txt file
How to do it I’m on Clion
Edit your CMake file or if you don't have that edit your Makefile
Not sure how your IDE matters here
Check out the add_compile_options command from CMake.
Could e.g. looks like so for a simple debug build:
add_compile_options(-Wall -Wextra -Wconversion -pedantic -Wfatal-errors -g3 -fsanitize=address)
ok I delete the & know I don’t have anymore this error but my programm still stopped
I mean you're also printing the value before you even set it using the fscanf.
That is also UB.
yes but oddly it works
does I have to add it here
add_compile_options(-Wall -Wextra -Wconversion -pedantic -Wfatal-errors -g3 -fsanitize=address)
If that's the highest level CMakeLists.txt file
yes it is
then yes
No change in the error
Example for how CMakeLists.txt could look like for a small project (from an old homework of mine):
- src
* .h files
* logger.cpp
* monitor.cpp
* run.cpp
* CMakeLists.txt
- ...
- CMakeLists.txt
And the CMakeLists.txt looked roughly like so:
# this is the root cmake configuration file for your homeworks.
# it sets up the project and (at the bottom) includes your homework code.
cmake_minimum_required(VERSION 3.14)
project(cppcourse)
# try to prevent in-source builds
if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")
message(FATAL_ERROR "In-source builds are not allowed. Please create a separate 'build' directory and build in there.")
endif()
# set default c++ standard for compile targets
set(CMAKE_CXX_STANDARD 20)
# require C++20, don't allow falling back to older version of standard
set(CXX_STANDARD_REQUIRED ON)
# disable C++ extensions
set(CMAKE_CXX_EXTENSIONS OFF)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()
#------- tweaks for an improved build experience -------
# so language servers like clangd know what the buildsystem does
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# display many warnings during compilation
add_compile_options(-Wall -Wextra -Wconversion -pedantic -Wfatal-errors)
#------- homework code inclusion -------
add_subdirectory("src")
```and the `src/CMakeLists.txt` looked like this:
```cmake
# list all the code files of the module
set(SOURCES logger.cpp monitor.cpp)
set(LIBRARY_NAME src)
set(EXECUTABLE_NAME runsrc)
add_library(${LIBRARY_NAME} ${SOURCES})
target_include_directories(${LIBRARY_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(${LIBRARY_NAME} PROPERTIES LINKER_LANGUAGE CXX)
target_compile_features(${LIBRARY_NAME} PUBLIC cxx_std_20)
add_executable(${EXECUTABLE_NAME} run.cpp)
target_link_libraries(${EXECUTABLE_NAME} ${LIBRARY_NAME} pthread)
What does the file content look like?
That's fine, but what does the file's content look like? The file you're reading from
Is that intended that you also store things like newline characters you read?
I mean... You have 18 characters per line and set the line size to 17. Idk how to even...
And you also only have 9 rows in your file
Not the 17 you specified
The space between count
space between what?
Yeah. I included those spaces when I derived at 18 characters per line
Count the characters yourself.
How many are there in the first line here?
- - - - - - - - -
abc
Wrong
That's not the same string (even if you replaced the B with a space)
This would be the same string:
;compile
print(len("- - - - - - - - -\n"))
18
And it also doesn't matter for you, as it's solely used to indicate the end of a string.
You don't have a string, you have a 2d array of characters
then I put minus 1 on each NbCol of the for loop
what?
there aren’t \n in my txt file but does it autamically made from the convertion ?
there aren’t \n in my txt file
(X) Doubt
? I don’t understand...
There are line breaks. So obviously there are newline characters.
We can even see them in this image of yours: #1304874352440901633 message and I even mentioned that before already: #1304874352440901633 message
ah okay I understand
Ok so is it the problem since it is taking into the map when it shouldn’t
I guess
If you copy this message you will see it's 2000 characters long
Not all characters have a textual representation.
The newline character is one of these, but since it creates a line-break it's still rather visible/apparent if one is there.
I mean I don't know if that's the actual problem, but it's definetly something you should fix first.
I can't really test run anything myself because all you're sending are screenshots
int loadGame(int *nbPlayers, struct Player P[], int *NbCol, char map[*NbCol][*NbCol]) {
FILE *file = fopen("..//last_party.txt", "r");
if (file == NULL) {
printf("No saved game found.\n");
return 0;
}
if (fscanf(file, "%d %d", nbPlayers, NbCol) != 2) {
printf("Error reading number of players and number of columns.\n");
fclose(file);
return 0;
}
printf("nb col %d\n\n",*nbPlayers);
for (int i = 0; i < *nbPlayers; i++) {
P[i].name = malloc(30 * sizeof(char));
if (fscanf(file, "%s %d %d %c %d %d %d", P[i].name, &P[i].nbBarriere, &P[i].color, &P[i].pawn, &P[i].posX, &P[i].posY, &P[i].score) != 7) {
printf("Error reading player data.\n");
fclose(file);
return 0;
}
}
for (int i = 0; i < *NbCol ; i++) {
for (int j = 0; j < *NbCol ; j++) {
if (fscanf(file, "%c", &map[i][j]) != 1) {
printf("Error reading map data at position (%d, %d) : %c.\n", i, j,map[i][j]);
fclose(file);
return 0;
}
printf("(%d, %d) : %c.\n", i, j,map[i][j]);
}
fscanf(file, "\n");
}
fclose(file);
return 1;
}
so change the condition to "&& i != 18"
Btw, that line
printf("Error reading map data at position (%d, %d) : %c.\n", i, j,map[i][j]);
```is UB because you just failed to store something into `map[i][j]`, so what do you get if you now try to read from that position?
UB ?
what?
Undefined behaviour - anything can happen
got this
I have to make the for loop an 18 iteration and 17 and When it’s the last elements to not put in the map
Why not just do it like so?
#define NbCol 17
int loadGame(int nbPlayers, struct Player *P, char map[NbCol][NbCol]) {
...
for (int row = 0; row < NbCol; row++) {
for (int col = 0; col < NbCol; col++) {
...
}
}
}
I never really understood why your nbPlayers and NbCol (very inconsistent naming btw) are pointers
and why NbCol even is a variable
NbCol can have 2 values so I didn’t put a #define
The value is taken from the txt file can be 17 or 23
depend on the board like the number of player that can be 2 or 4
same error
for (int row = 0; row < *NbCol; row++) {
for (int col = 0; col < *NbCol; col++) {
if (fscanf(file, "%c", &map[row][col]) != 1) {
printf("Error reading map data at position (%d, %d) : %c.\n", row, col,map[row][col]);
fclose(file);
return 0;
}
printf("(%d, %d) : %c.\n", row, col,map[row][col]);
}
fscanf(file, "\n");
}
Okay.
Then I would've chosen a data layout like this:
typedef enum field Field;
enum field {
EMPTY, B, WHATEVER_ELSE_STATES_YOU_NEED
};
int translate_index(int row, int col, int board_size) {
return row * board_size + col;
}
...
int board_size = /* extract board size from the text file */
Field *board = malloc(board_size * board_size * sizeof *board);
board[translate_index(2, 3, board_size)] = EMPTY; // access and set 2nd row, 3rd column of the board
It's almost always easier to work with 1d arrays than it is working with multi-dimensional ones.
Not to mention that we're finally not using a VLA anymore.
yeah sure but I don’t really understand since I’ve never seen enum
An enum is just a bunch of aliases for integers.
E.g. in my case EMPTY is the same as 0, B is the same as 1 and WHATEVER_ELSE_STATES_YOU_NEED is the same as 2.
But as you can see the aliases EMPTY or B are much more descriptive to your task than 0 or 1
okay I understand
So
typedef enum field Field;
enum field {
EMPTY, B, WHATEVER_ELSE_STATES_YOU_NEED
};
int translate_index(int row, int col, int board_size) {
return row * board_size + col;
}
int loadGame(int *nbPlayers, struct Player P[], int *NbCol, char map[*NbCol][*NbCol]) {
...
int board_size = NbCol;
Field *board = malloc(board_size * board_size * sizeof *board);
board[translate_index(2, 3, board_size)] = EMPTY; // access and set 2nd row, 3rd column of the board
for (int row = 0; row < *NbCol ; row++) {
for (int col = 0; col < *NbCol +1; col++) {
if(col != 18 || row!=0 && col!=0) {
if (fscanf(file, "%c", &map[row][col]) != 1) {
printf("Error reading map data at position (%d, %d) : %c.\n", row, col,map[row][col]);
fclose(file);
return 0;
}
}
printf("(%d, %d) : %c.\n", row, col,map[row][col]);
}
fscanf(file, "\n");
}
fclose(file);
return 1;
}
But don’t that ask to change the whole structure of the game since I use no more map but an enum ?
OMG! I just realized that in your original code you declare the array before you even know the size.
How is that supposed to work?
IDK I put with the max size
don’t really know how to do since it is in another file where I edit this in unsaved game
Since it doesn’t implicate the for loop...
I change it
creates a new error 😦
Okay, so I will now do something that I typically try to avoid, which is to basically rewrite your entire project for you.
But you're so knees deep into an approach that is just flawed in so many ways.
This is only a re-write to the point where you were already, but it'll be much nicer to work with for the entire rest of the program.
Make sure to understand what is happening here.
I will use a char instead of the Field enum, just because I don't really know where you'll want to go with this and maybe a char would actually be easier.
I will also shorten a few things cause I don't want to reconstruct your entire Player struct.
typedef struct player Player;
struct player {
char *name;
...
};
typedef struct game Game;
struct game {
char *board;
unsigned board_size;
Player *players;
unsigned player_count;
};
unsigned translate_index(unsigned row, unsigned col, Game *game) {
return row * game->board_size + col;
}
Game *load_game(const char *filepath) {
FILE *file = fopen(filepath, "r");
if (!file) {
printf("No saved game found.\n");
return NULL;
}
Game *game = malloc(sizeof *game);
if (fscanf(file, "%d %d", &game->player_count, &game->board_size) != 2) {
printf("Error reading number of players and number of columns.\n");
fclose(file);
return NULL;
}
Player *players = malloc(game->player_count * sizeof *players);
game->players = players;
for (int i = 0; i < game->player_count; i++) {
players[i].name = malloc(30);
if (fscanf(file, "%s ...", players[i].name, ...) != 7) {
printf("Error reading player data.\n");
fclose(file);
return NULL;
}
}
char *board = malloc(game->board_size * game->board_size);
Game->board = board;
for (int i = 0; i < game->board_size; i++) {
for (int j = 0; j < game->board_size; j++) {
char thing = fgetc(file);
if (thing == EOF) {
printf("Error reading map data at position (%d, %d).\n", i, j);
fclose(file);
return NULL;
}
board[translate_index(i, j, game)] = thing;
printf("(%d, %d) : %c.\n", i, j, board[i][j]);
}
char buf[1000];
fgets(buf, sizeof buf, file); // read until we've read the newline character
}
fclose(file);
return game;
}
int main() {
Game *game = load_game("..//last_party.txt");
if (!game) {
return 1;
}
}
Please note that code is untested as I just drew it up here in Discord
@toxic shell
@toxic shell Has your question been resolved? If so, type !solved :)
sorry but it has some problems
like the type Players in "Player *players;" from the struct game Game isn’t recognize
ok I corrected it
!solved