Creating a game board using struct - c

So I am making a game board for battle ship, but I am trying to use a struct to make it. Currently I am getting an error when trying to create the game board. I'm trying to make it this way so that when the user inputs coordinates for the ships, or when they are making a move I can easily change symbols and get to the correct coordinate on the array. This is what I am working with right now. I am using 3 file format, so I put all the parts down below.
I could create the board without using a struct, but I'm pretty sure I need to create it this way so that I am able to manipulate the board later.
If this helps this is my current error: Run-Time Check Failure #3 - The variable 'person' is being used without being initialized.
This is in the header file
typedef struct game_board
{
int board[10][10];
int row;
int col;
char symbol;
}Game_Board;
Game_Board initalize_game_board(Game_Board player);
The function
Game_Board initalize_game_board(Game_Board player)
{
int row_index = 0, col_index = 0;
printf(" 0 1 2 3 4 5 6 7 8 9\n");
for (row_index = 0; row_index < player.row; row_index++)
{
printf("%d ", row_index);
for (col_index = 0; col_index < player.col; col_index++)
{
player.board[row_index][col_index] = player.symbol;
printf("%c ", player.board[row_index][col_index]);
}
printf("\n");
}
}
In the main function
int main(void)
{
FILE *outfile = NULL;
outfile = fopen("battleship.log", "w");
Game_Board person, computer;
int who_goes_first = 0;
strcpy(person.symbol, '~');
person.row = 10;
person.col = 10;
strcpy(computer.symbol, '~');
computer.row = 10;
computer.col = 10;
welcome_screen(outfile);
printf("Player 1\n");
initalize_game_board(person);

You need return statements for both functions. Ending paren for main().
Highly recommend
computer.symbol = '~';
Instead of
strcpy(computer.symbol, '~');

Building on Ryan's answer, strcpy() assumes the source string has a null terminator, to know how many characters are to be copied. In your case, there is no null terminator in the source string. strcpy() will not stop copying till a null character is read from memory. Since you are using a single character, a simple assignment statement will do!
Also, in function initalize_game_board(), consider passing the pointer to the Game_Board structure, instead of the structure itself. When you do this, you can change the contents of the actual structure (struct 'person' in this case), by using the arrow (->) operator, within the function itself. Then you will not have to return the structure from this function. With your current design, you are creating a temporary copy of the structure, then populating it, and then (probably after modifications!) returning that structure, which will again be copied to the structure 'person'.

Related

Stored data is not same which I can access in file read loop

I have to read a txt with data in it. I can read it and store the data, but I don't know why, some stored data is not good after the read method.
Here is my output:
I write out these data with exactly the same code, except that the first is inside the loop and the second is outside of the loop.
I store these data in their own struct arrays. So as you can see, my problem is that I can't access my data outside that loop. What could be wrong?
Here is the full code: https://pastebin.com/wzEJqcZG
And the test data: https://pastebin.com/L7J133mz
This is inside the file read loop:
printf("%c %i - ", sorok[i].futarkod, sorok[i].datum);
for(j=0;j<sorok[i].rendelesCount;j++) {
printf("%i%c", sorok[i].rendelesek[j].db, sorok[i].rendelesek[j].fajta);
}
printf("\n");
And this is outside of the file read loop:
for(i=0;i<5;i++) {
printf("%c %i - ", sorok[i].futarkod, sorok[i].datum);
for(j=0;j<sorok[i].rendelesCount;j++) {
printf("%i%c ", sorok[i].rendelesek[j].db, sorok[i].rendelesek[j].fajta);
}
printf("\n");
}
In the output the first two columns are good, just the text after the dash is not.
test.c:65:14: warning: 'sor' may not be used as an array element due to flexible array member
[-Wflexible-array-extensions]
sor sorok[32];
^
rendeles rendelesek[]; is a flexible array member meaning since it's at the end of the struct you can, in theory, allocate as much memory for the array as you like. However this means the size of any given sor will vary.
Each element of an array in C must be of a fixed size, going from one element to another is simply start-of-array-memory + (i * sizeof(element)). Since sor can be of different sizes it can't be put into an array.
You could use an array of pointers to sor, or you can change sor to contain a pointer to rendeles **rendelesek;. Or both, getting used to working with pointers is good.
The real problem is sor.rendelesek is never allocated. Whichever you choose, you still have to allocate memory to sor.rendelesek else you're writing into someone else's memory. As a flexible array member, you have to use a pointer array and allocate sufficient memory as part of sor.
typedef struct {
char futarkod;
int datum;
int rendelesCount;
rendeles rendelesek[];
} sor;
sor *sorok[32];
for( size_t i = 0; i < 32; i++) {
sorok[i] = malloc(sizeof(sor) + (sizeof(rendeles) * 32));
}
Or you can use a rendelesek ** instead and allocate that directly. Combining both is probably the best option.
typedef struct {
char futarkod;
int datum;
int rendelesCount;
rendeles *rendelesek;
} sor;
sor *new_sor(const size_t num_rendeles) {
sor *new = malloc(sizeof(sor));
new->rendelesek = malloc(sizeof(rendeles) * num_rendeles);
return new;
}
int main()
{
sor *sorok[32];
for( size_t i = 0; i < 32; i++) {
sorok[i] = new_sor(32);
}
Reading inputs into statically allocated structures like this is risky and wasteful because you have to allocate what you think is the most possible elements. It's very easy to allocate way too much or not enough. Instead they should be dynamically allocated as needed, but that's another thing.

How to initialize these pointers?

I need to make a list of employees and I can't change these structures, I'm having trouble in how to initialize each of tab[10] to NULL and how to set values
#include <stdio.h>
#include <stdlib.h>
typedef struct employee Employee;
struct employee{
char name[81];
float salary;
};
Employee *tab[10]; /*a table with employee*/
void set(Employee **tab, int i, char *name, float salary){
tab[i]->name = name;
tab[i]->salary = salary;
}
int main(){
Employee *e;
int i = 0;
for(; i < 10; i++) init(i,&e);
return 0;
}
/*a table with an employee, each position must have a name and a salary*/
Employee *tab[10];
void init(int n, Employee **tab);
Everaldo
With commentators helping you, it seems you are getting there. I would like to sum up the suggests given so far and add a couple of my own.
Declaring the Employee array
Declaring the array as a global variable and then passing it as a parameter to functions makes things a little confusing. I usually prefer declaring a local variable and then passing it to the various functions that uses it. Also as suggested by David C. Rankin, to initialize every array element to 0 just requires you to initial the first element in the declaration statement. No FOR loop needed. The compiler will auto initialize the rest of the array elements for you.
main()
{
Employee* tab[10] = { NULL };
. . . .
}
Array memory allocation
As mention by Patrick87, you need to add code to assign memory to every element in the array. An example initialization routine could be coded as follows:
int init(int len, Employee** tab) {
int i = 0;
for (i = 0; i < len; i++)
{
if ( (tab[i] = (Employee*) calloc (1,sizeof(Employee))) == NULL )
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Function usage:
if (init(10, &tab) == EXIT_FAILURE)
{
puts("CALLOC Failed, aborting....");
exit(EXIT_FAILURE);
}
Things to note:
Check to ensure the memory was allocated. On failure return some
type of failure status to alert the caller of the function.
The status codes that are being returned are define in stdlib.h.
They are not necessary but do give a clear indication to the reader
of your code the success and failure paths your code takes.
The FOR loop was moved inside the initialization function. Function
calls are expensive when it comes to processing time. Since the
array size is known, it is faster to perform the loop inside the
function.
Try to always write functions that return a status. This will enable
the caller to perform any error handling if the function's operations
fail.
Set array element values
The following statement is not valid. You cannot directly copy the content from a string pointer to an array of characters. You will need to use statements like strcpy, strncpy, or memcpy to copy the data.
tab[i]->name = name;
There is a method I prefer for copying strings.
sprintf(tab[i]->name, "%.80s", name);
This will copy up to 80 characters from name into tab[i]->name, then insert a null character. The beauty of this statement is that the designation variable does not have to be the same size as the source. If the source variable (in this case name) is shorter, spirntf will simply stop when it encounter a null character and then null terminate the destination string. If the source is longer than 80 characters or if it is missing the null terminator character, sprintf will stop coping at the 80st character position and then auto insert a null character in the 81st character position.
An example SET routine could look like the following:
void set(Employee** tab, int i, char* name, float salary) {
sprintf(tab[i]->name, "%.80s", name);
tab[i]->salary = salary;
}
Usage:
for (i = 0; i < 10; i++)
{
set(&tab, i, "Bob", 35000. + i); // bogus values, demo purposes only
}
Main program logic
Your main program as you currently have outline will need to change. For starters, the declaration of variable “e” should be replace with the declaration of variable “tab” (see Patrick87 comments) . On initializing the array, see my suggestion above. To set values to the array elements see SET function comments above.
Free memory
Every time you allocate memory, you must free it when you are done. Forgetting to free allocated memory will create memory leaks in your program. Note technically, in this demonstration program, the system will free the memory when your code exits, so you do not need to free it. But it is good practice so when you start writing real applications you will not forget to do so.
Here is an example on how this could be done:
for (i = 0; i < 10; i++)
free (tab[i]);
tab is an array of pointers, so to initialize them all to NULL, you can use a for loop, e.g.
for (i = 0; i < n; i++)
tab[i] = 0;
To set a value, allocate some space for an instance of your struct (either on the stack via function parameter or local variable, or else on the heap by with malloc/calloc/realloc) and then set one of the tab[k] to the address of the memory you allocated (using & or just the pointer directly if allocated).

Trouble looping through arrays define in other source files

I have asked a question somewhat related to this this before asking why cant i return the array size from a malloc/calloc (i have received an answer to this).
My current question is i have 2 arrays defined and fill in two separate source files ship.c and rescue_assets.c. I am attempting to loop through them in a method inside a file called system_handler.c.
The trouble i am having is that this task requires that you DO NOT hardcore an array size into the code so i don't see how i can link the array size from each c file into this function in the 3rd c file.
Ultimately i would like:
assign_mayday_to_ships(int SIZE_OF_ARRAY_FROM_FILE_1, int SIZE_OF_ARRAY_FROM_FILE_2){
for(int i=0; i < SIZE_OF_ARRAYFROM_FILE_1; i++){
for(int j = 0; < SIZE_OF_ARRAYFROM_FILE_2; j++{
//do something
}
}
i could easily do this if they were in the same file, but i can't call that method from two different files, because it would obviously lack the parameters required.
Here is the code in question ( ive only added the required snippets, all headers are included and the system runs as intended bar getting the array sizes):
system_handler.c
void assign_mayday_to_ships() {
mayday_call* mday_ptr;
ship* ship_ptr;
rescue_asset* assets_ptr;
mday_ptr = read_mayday_file();
ship_ptr = read_ship_locations();
assets_ptr = read_recuse_assets();
int i;
int result;
/* loop through ship locations to find the ship that called the mayday
When found assign the mayday call to the ship for use when sending help*/
for (i = 0; i < arr_size; i++) {
result = strncmp(mday_ptr->ais, (ship_ptr + i)->ais, COMPARE_LIMIT);
if (result == 0) {
mday_ptr->ship = (ship_ptr + i);
}
}
calc_distance_to_mayday(mday_ptr, assets_ptr);
}
rescue_asset.c: assets is the array i want to get the size of.
rescue_asset* assets;
no_of_lines = count_lines(locof);
printf("number of lines = %d \n", no_of_lines);
assets = calloc(no_of_lines,sizeof (rescue_asset));
ship.c: ships is the array want to get the size of.
ship* ships;
/* -1 because first line of file is not a ship location*/
no_of_lines = (count_lines(locof) - 1);
ships = calloc(no_of_lines, sizeof (ship));
Would it be better to use actual arrays rather than calloc and such?
Thanks,
Chris.
You have to pass in the number of items you have allocated as an argument to the function. If you can't do that (like in you r case where those are allocated in called functions) you can return it by either having the size added as a pointer argument to the function which does the allocation (passing by reference), or by returning a structure containing the pointer and the size.
For the first, you can do something like
size_t asset_size;
asset *assets_ptr = read_recuse_assets(&asset_size);
Then in read_recuse_assets you set *asset_size to the correct size.
Of course, you can do the opposite with the pointer and size, and pass a pointer to assets_ptr as argument and returning the size.
More complete example:
asset *read_recuse_assets(size_t *asset_size)
{
...
*asset_size = no_of_lines;
return assets;
}
Call as outlined above.
For the second alternative, you can have a structure like this:
struct asset_data
{
size_t size;
asset *assets;
};
Then return an instance (not pointer) of this structure with the field filled in.

C pass size of an array to another c file variable

**Issue overview **
The current issue i have is that i have an array which has the size of a variable which happens to be the amount of lines in a file. This is an integer which is calculated and returned, which becomes the arraysize (e.g. file text.txt has 12 lines so the array is of size 12).
I want to know how i can return this value to another c file for use in a function so i can loop through the complete array.
points to note
I am not allowed any globals at all in this assignment, no global arrays/variables at all.
The line counting functions works correctly so i will not be posting it here
The array is set up correctly and print the correct results
Most of the code from the functions has been removed to make it easier to read.
The correct #includes for each file are present, i just need an example of how to do it.
The code:
void read_from_file() {
/* reading and parsing removed */
no_of_lines = (count_lines(locof) - 1);
/* locof is a char array storing the file name */
ship ships[no_of_lines];
/* i want to return the value of no_of_lines *?
I want to return the value of no_of_lines
The c file where i need the value
/*This is where i need the variable */
void asign_mayday_to_ships() {
int* ship_arr_length = SIZE OF SHIP ARRAY NEEDED
mayday_call* mday_ptr;
ship* ship_ptr; /* this is a ship array */
mday_ptr = read_mayday_file();
ship_ptr = read_ship_locations();
int i;
for(i = 0; i < SIZE OF SHIP ARRAY; i++){
}
Just pass both pointer and size, it'a a C way.
void read_from_file() {
/* reading and parsing removed */
no_of_lines = (count_lines(locof) - 1);
/* locof is a char array storing the file name */
ship ships[no_of_lines];
some_fun_from_second_file(ships, no_of_lines);
Who calls the two fnctions? Can't you just return the nr of lines in an upper function then pass it in the second one? If not, then you must somehow store it in a variable(or a struct member) and then you can grab it later. This is a contextual solution, it might not work for you.
i had to first malloc my ships array, then set the size of the malloc depending on the amount of elements then i can return the size of the pointer:
ship* ships;
ships = malloc(sizeof (ship) * no_of_lines);
the in the function i was having trouble with:
mayday_call* mday_ptr;
ship* ship_ptr;
mday_ptr = read_mayday_file();
ship_ptr = read_ship_locations();
int arr_size = sizeof (ship_ptr) ;
int i;
for(i =0; i < arr_size; i++) {
//do something
}
`
sounds like your 'teacher' wants make you use a sentinel value. Ie put an object at the end of the array that cannot exist (a ship with name all spaces for example) then in the array processing you keep looping till you hit the magic value.
This is a bad design, but if you aren't allow globals and you aren't allow parameters I cant see what else to do

Dynamic Memory storage issue after realloc - C

For an assignment at school, we have to use structs to make matrices that can store a infinite amount of points for an infinite amount of matrices. (theoretical infinite)
For the assignment I decided to use calloc and realloc. How the sizes for the matrix go is: It doubles in size every time its limit is hit for its points (so it starts at 1, then goes to 2, then 4 and so on). It also doubles in size every time a matrix is added as well.
This is where my issue lies. After the initial matrix is added, and it goes to add the second matrix name and points, it gives me the following:
B???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
B is the portion of it that I want (as I use strcmp later on), but the ? marks are not supposed to be there. (obviously)
I am not sure why it is exactly doing this. Since the code is modular it isn't very easy to get portions of it to show exactly how it is going about this.
Note: I can access the points of the matrix via its method of: MyMatrix[1].points[0].x_cord; (this is just an example)
Sample code that produces problem:
STRUCTS:
struct matrice {
char M_name[256];
int num_points[128];
int set_points[128];
int hasValues[1];
struct matrice_points * points;
} * MyMatrix;
struct matrice_points {
int set[1];
double cord_x;
double cord_y;
};
Setup Matrix Function:
void setupMatrix(){
MyMatrix = calloc(1, sizeof(*MyMatrix));
numMatrix = 1;
}
Grow Matrix Function:
void growMatrix(){
MyMatrix = realloc(MyMatrix, numMatrix * 2 * sizeof(*MyMatrix));
numMatrix = numMatrix * 2;
}
Add Matrix Function which outputs this problem after growing the matrix once.
void addMatrix(char Name, int Location){
int exists = 0;
int existsLocation = 0;
for (int i = 0; i < numMatrix; i++){
if (strcmp(MyMatrix[i].M_name, &Name) == 0){
exists = 1;
existsLocation = i;
}
}
*MyMatrix[Location].M_name = Name;
printf("Stored Name: %s\n", MyMatrix[Location].M_name);
*MyMatrix[Location].num_points = 1;
*MyMatrix[Location].set_points = 0;
*MyMatrix[Location].hasValues = 1;
MyMatrix[Location].points = calloc(1, sizeof(*MyMatrix[Location].points));
}
void addMatrix(char Name, int Location)
char Name represents a single char, i.e. a integer-type quantity. char is just a number, it's not a string at all.
When you do this:
strcmp(..., &Name)
you're assuming that the location where that one character is stored represents a valid C string. This is wrong, there is no reason why this should be the case. If you want to pass a C string to this function, you will need to declare it like this:
void addMatrix(char *Name, int Location)
Then you need to copy that C string into the appropriate place in your matrix structure. It should look like:
strncpy(... .M_name, Name, max_number_of_chars_you_can_store_in_M_Name);
Also these field definitions are strange in your struct:
int num_points[128];
int set_points[128];
int hasValues[1];
This means that your struct will contain an array of 128 ints called num_points, another array of 128 ints calls set_points, and an array of one int (strange) called hasValues. If you only need to store the count of total points and set points, and a flag indicating whether values are stored, the definition should be:
int num_points;
int set_points;
int hasValues;
and correct the assignments in your addMatrix function.
If you do need those arrays, then your assignments as they are are wrong also.
Please turn on all warnings in your compiler.
Try adding '\0' to the end of your data.
*MyMatrix[Location].M_name = Name;
You're copying a single character here, not a string. If you want a string, Name should be defined as char *, and you should be using strcpy.

Resources