Segmentation error due to the use of a char ** - c

I have to program a function that browses a map that I have previously stored in a char **. At each char I have to check if the 8 characters that surround it and check if on these 9 there are at least 2 that correspond to '#', so I created a struct *matrix that is supposed to check this.
I am only allowed to use the following functions/system calls: malloc, free, exit, (f)open, (f)close, (f)read, (f)write, getline, ioctl, usleep, sigaction, signal, stat, lstat, fstat
The problem is that despite the fact that I check if the array exists, the program returns a segmentation fault.
Here are the 2 functions that concern the matrix structure:
matrix_t *create_matrix(char **map, size_t y, size_t x)
{
matrix_t *out = malloc(sizeof(matrix_t));
if (!out) {
my_perr("[ERROR] Memory's allocation failure\n");
}
out->nbr = 0;
set_mat_nbr(out, map, y - 1, x);
set_mat_nbr(out, map, y, x);
set_mat_nbr(out, map, y + 1, x);
return out;
}
void set_mat_nbr(matrix_t *matrix, char **map, long y, long x)
{
if (y != 0 && map[y] != NULL && x != 0 && map[y][x - 1] == '#') {
matrix->nbr++;
}
if (y != 0 && map[y] != NULL && map[y][x] == '#') {
matrix->nbr++;
}
if (y != 0 && map[y] != NULL && map[y][x + 1] == '#') {
matrix->nbr++;
}
}
And here is the calling function (This one is not finished yet and only checks the top border for the moment) :
void check_border(char **map)
{
size_t y = 0, x = 0;
matrix_t *matrix = NULL;
while (map[0][x] != '\0') {
matrix = create_matrix(map, 0, x);
if (matrix->nbr < 2) {
my_perr("[ERROR] Corrupted border\n");
}
free(matrix);
x++;
}
}
According to valgrind, the segfault is triggered on the 3 if() of set_mat_nbr().
Do you know what is wrong with my code?

Thank you all, I have corrected the problem and everything works now. Here is the new code:
void set_mat_nbr(matrix_t *matrix, char **map, size_t y, size_t x)
{
if (x == 0) {
(map[y][x] == '#') ? matrix->nbr++ : 0;
(map[y][x + 1] == '#') ? matrix->nbr++ : 0;
} else if (map[y][x] == '\0') {
(map[y][x - 1] == '#') ? matrix->nbr++ : 0;
(map[y][x] == '#') ? matrix->nbr++ : 0;
} else {
(map[y][x - 1] == '#') ? matrix->nbr++ : 0;
(map[y][x] == '#') ? matrix->nbr++ : 0;
(map[y][x + 1] == '#') ? matrix->nbr++ : 0;
}
}
And :
matrix_t *create_matrix(char **map, size_t y, size_t x)
{
matrix_t *out = malloc(sizeof(matrix_t));
if (!out)
my_perr("[ERROR] Memory's allocation failure\n");
out->nbr = 0;
if (y == 0) {
if (!map[y + 1]) {
set_mat_nbr(out, map, y, x);
} else {
set_mat_nbr(out, map, y, x);
set_mat_nbr(out, map, y + 1, x);
}
} else if (!map[y + 1]) {
set_mat_nbr(out, map, y, x);
set_mat_nbr(out, map, y - 1, x);
} else {
set_mat_nbr(out, map, y - 1, x);
set_mat_nbr(out, map, y, x);
set_mat_nbr(out, map, y + 1, x);
}
return out;
}

Related

How can I have this grid wrap around on all sides?

I have an assignment where I need to let the user create the height and width of a grid. Then be able to place "ships" onto that grid at any x and y coordinates. Then you can place a storm on a certain section of that grid to then prompt and see if a storm is overlapped with a ship. I have done that successfully but I can't get the storm to wrap around the grid. For example if the grid is 20x20 and I put a storm that starts on the 20th spot over it should shift to the 1 position on the left side of the grid. Here is that code I have a diagram of what it looks like. (Note there is no physical grid getting printed to the terminal)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct ship {
// Declaring variables
char shipName[21];
int x, y, w, h;
char direction;
struct ship *next;
} Ship;
//Declaring head of linked list
Ship *head = NULL;
void newShip(int x, int y, char direction, char *shipName) {
//Adding ships to linked list
Ship *new_ship = (Ship *)malloc(sizeof(Ship));
strcpy(new_ship->shipName, shipName);
new_ship->x = x;
new_ship->y = y;
new_ship->direction = direction;
new_ship->next = head;
head = new_ship;
}
void shipMovement(int time, int w, int h) {
//Moving ships
Ship *current = head;
while (current != NULL) {
if (current->direction = 'U') {
current->y = (current->y + time) % h;
}
else if (current->direction = 'D') {
current->y = (current->y - time + h) % h;
}
else if (current->direction = 'L') {
current->x = (current->x - time + w) % w;
}
else if (current->direction = 'R') {
current->x = (current->x + time) % w;
}
else {
printf("Invalid Direction!\n");
}
current = current->next;
}
}
void checkAffShips(int x, int y, int w, int h, char **affShips, int *numAffShips) {
//Checking if ships are affected by storm
Ship *current = head;
while (current != NULL) {
if (((current->x >= x) && (current->x < x + w)) && ((current->y >= y) && (current->y < y + h))) {
// add shipName to list of affected ships
affShips[*numAffShips] = (char *)malloc(sizeof(char) * 21);
strcpy(affShips[(*numAffShips)++], current->shipName);
}
current = current->next;
}
}
//Main Function------------------------------------------------------------------
int main() {
int w, h;
int stormWidth, stormHeight;
scanf("%d %d", &w, &h);
char userInput;
//Looping through commands
while (scanf(" %c", &userInput) != 4) {
if (userInput == '1') {
int x, y;
char direction[21], shipName[21];
scanf("%d %d %s %s", &x, &y, direction, shipName);
newShip(x, y, direction[0], shipName);
} else if (userInput == '2') {
int time;
scanf("%d", &time);
shipMovement(time, w, h);
} else if (userInput == '3') {
int x, y, w, h;
scanf("%d %d %d %d", &x, &y, &w, &h);
char *affShips[1000];
int numAffShips = 0;
checkAffShips(x, y, w, h, affShips, &numAffShips);
printf("%d\n", numAffShips);
for (int i = 0; i < numAffShips; i++) {
printf("%s\n", affShips[i]);
free(affShips[i]);
}
} else if (userInput == '4') {
break;
}
else {
printf("Invalid Input!\n");
}
}
return 0;
}
Here is the documentation:
(https://i.stack.imgur.com/K28We.png)
I've tried a bunch of different stuff so maybe I just didn't do something right in my attempts but I'm sure someone can help figure this out.
Your test for the affected ships is wrong. In your example, if you have a storm of size 2 in the bottom right corner (19, 19), a ship in the top left corner (0, 0) isn't caught, because 0 is not in the range [19, 21).
One way to fix this is to move the point you want to test into the "extended range" if it lies below the starting point of the storm. (The "extended range" is the range that does not wrap and so extends to two times the width of the board.)
So to test whether a one-dimensional point lies in a cyclic range, you could use a function like this:
int in_cyclic_range(int n, int lower, int width, int wrap)
{
if (n < lower) n += wrap;
return (n < lower + width);
}
If you now test n in the whole range from [0, 20) on the storm at 19 of width 2, with in_cyclic_range(n, 19, 2, 20), you will get hits at locations 19 and 0.
In order to test if a ship is affected by a storm, you need the storm position and dimensions, the ship position and the grid dimensions.
In your code, you use w, and h for the grid dimensions and a new set of variables w and h for the storm dimensions in the local scope of if (userInput == '3') { ... }. This is confusing and makes the grid dimensions inaccessible from this part of the code. You should use stormWidth and stormHeight for the storm dimensions and pass both these and the grid dimensions to the checkAffShips function.
The test in checkAffShips for the wrapped coordinate system is more complicated than what you wrote to take into account the wrapped parts of the storm area: as many as 3 extra rectangles.
Also note these issues:
using explicit names for the grid and storm dimensions would help avoid confusion.
the w and h fields in the Ship structure are unused.
reading strings with scanf should be protected by specifying the maximum number of characters to store into the destination array before the null terminator.
newShip should not use strcpy directly as the shipName argument could be longer than the destination array.
you should check the return value of scanf() to detect invalid or missing input.
if (current->direction = 'U') sets current->direction and evaluates to true. You should use == instead of =
the array of shipnames affShips should be allocated by checkAffShips.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct ship {
char shipName[21];
int x, y;
char direction;
struct ship *next;
} Ship;
//Declaring head of linked list
Ship *head = NULL;
/* string copy function with size limitation */
void mystrcpy(char *dest, size_t size, const char *src) {
while (size > 1) {
*dest++ = *src++;
size--;
}
if (size > 0)
*dest = '\0';
}
void newShip(int x, int y, char direction, const char *shipName) {
//Adding ship to linked list
Ship *new_ship = (Ship *)malloc(sizeof(*new_ship));
if (new_ship) {
mystrcpy(new_ship->shipName, sizeof new_ship->shipName, shipName);
new_ship->x = x;
new_ship->y = y;
new_ship->direction = direction;
new_ship->next = head;
head = new_ship;
}
}
void shipMovement(int time, int w, int h) {
//Moving ships
for (Ship *current = head; current != NULL; current = current->next) {
if (current->direction == 'U') {
current->y = (current->y + time) % h;
} else
if (current->direction == 'D') {
current->y = (current->y + h - time % h) % h;
} else
if (current->direction == 'L') {
current->x = (current->x + w - time % w) % w;
} else
if (current->direction == 'R') {
current->x = (current->x + time) % w;
} else {
printf("%s: invalid Direction '%c'!\n",
current->shipName, current->direction);
}
}
}
char **checkAffShips(int stormX, int stormY, int stormWidth, int stormHeight,
int gridWidth, int gridHeight,
int *pnumAffShips)
{
char **affShips = NULL;
int numAffShips = 0;
for (Ship *current = head; current != NULL; current = current->next) {
int x = current->x;
int y = current->y;
//Checking if ship is affected by storm
if (((x >= stormX && x < stormX + stormWidth) ||
(stormX + stormWidth > gridWidth && x < (stormX + stormWidth) % gridWidth)) &&
((y >= stormY && y < stormY + stormHeight) ||
(stormY + stormHeight > gridHeight && y < (stormY + stormHeight) % gridHeight)))
{
// add shipName to list of affected ships
affShips = realloc(affShips, sizeof(*affShips) * (numAffShips + 1));
affShips[numAffShips++] = strdup(current->shipName);
}
}
*pnumAffShips = numAffShips;
return affShips;
}
//Main Function------------------------------------------------------------------
int main() {
int gridWidth, gridHeight;
if (scanf("%d %d", &gridWidth, &gridHeight) != 2)
return 1;
char userInput;
//Looping through commands
while (scanf(" %c", &userInput) == 1) {
if (userInput == '1') {
int x, y;
char direction[21], shipName[21];
if (scanf("%d %d %20s %20s", &x, &y, direction, shipName) != 4)
return 1;
newShip(x, y, direction[0], shipName);
} else
if (userInput == '2') {
int time;
if (scanf("%d", &time) != 1)
return 1;
shipMovement(time, gridWidth, gridHeight);
} else
if (userInput == '3') {
int x, y, stormWidth, stormHeight;
if (scanf("%d %d %d %d", &x, &y, &stormWidth, &stormHeight) != 4)
return 1;
char **affShips;
int numAffShips = 0;
affShips = checkAffShips(x, y, stormWidth, stormHeight,
gridWidth, gridHeight, &numAffShips);
printf("%d\n", numAffShips);
for (int i = 0; i < numAffShips; i++) {
printf("%s\n", affShips[i]);
free(affShips[i]);
}
free(affShips);
} else
if (userInput == '4') {
break;
} else {
printf("Invalid Input!\n");
}
}
return 0;
}

How can i malloc a char **

I have to code a battleship game for school so i'm trying to generate the map on which the players are going to place their boats, i have a segfault but i don't see why.
Here's my code :
Main :
int main(int ac, char **av)
{
map_data map_data;
print_map(map_gen(map_data));
return(0);
}
Struct :
typedef struct map_data {
int lines;
int letters;
int width;
int height;
}map_data;
Map generation :
char **map_gen(map_data map_data)
{
map_data.lines = 0;
map_data.width = 18;
map_data.height = 10;
map_data.letters = 65;
char **map = malloc(sizeof((char)18 * 10));
for (int s = 0; s <= map_data.height ; s++) {
for (int c = 0; c <= map_data.width; c++) {
map_fill(map, map_data, s, c);
}
}
return (map);
}
Filling of the char **map :
void char_fill(char **map, char ch, int s, int c)
{
map[s][c] = ch;
}
void map_fill(char **map, map_data map_data, int s, int c)
{
if (c == 1)
char_fill(map, '|', s, c);
if (s == 1)
char_fill(map, '-', s, c);
if (c == map_data.width)
char_fill(map, '\n', s, c);
map_fill2(map, map_data, s, c);
}
int map_fill2(char **map, map_data map_data, int s, int c)
{
if (s == 0 && c == 0)
char_fill(map, ' ', s, c);
if (s == 1 && c == 1)
char_fill(map, '+', s, c);
if (c > 1 && c % 2 == 0)
char_fill(map, '.', s, c);
if (s > 1 && c % 2 == 1)
char_fill(map, ' ', s, c);
if (s == 10 && c == 18)
char_fill(map, '\0', s, c);
if (s > 1 && c == 0) {
char_fill(map, my_int_to_char(map_data.lines), 0, 0);
map_data.lines = map_data.lines + 1;
}
if (!map[s][c]) {
my_putstr("error filling the map, please try again.");
return (EXIT_FAILURE);
}
}
Print :
void print_map(char **map)
{
int h = 0;
int w = 0;
while (map[h][w] != '\0') {
while (map[h][w] != '\n') {
my_putchar(map[h][w]);
w = w + 1;
}
h = h + 1;
}
}
Am i doing something wrong ?
Any tips on how to improve my code ?
Thanks
you do not need a pointer to pointer only 2D array for it.
Use the correct types.
Wrap the data into your structure. Do noy use separate data structures without need
Indexes in C atart from 0.
typedef struct map_data {
size_t lines;
size_t letters;
size_t width;
size_t height;
char map[];
}map_data;
int map_fill2(map_data *map, size_t s, size_t c);
void char_fill(map_data *map, char ch, size_t s, size_t c)
{
char (*cmap)[map -> width] = (char (*)[map -> width])map -> map;
cmap[s][c] = ch;
}
void map_fill(map_data *map, size_t s, size_t c)
{
if (c == 0)
char_fill(map, '|', s, c);
if (s == 0)
char_fill(map, '-', s, c);
if (c == map -> width - 1)
char_fill(map, '\n', s, c);
map_fill2(map, s, c);
}
int map_fill2(map_data *map, size_t s, size_t c)
{
char (*cmap)[map -> width] = (char (*)[map -> width])map -> map;
if (s == 0 && c == 0)
char_fill(map, ' ', s, c);
if (s == 1 && c == 1)
char_fill(map, '+', s, c);
if (c > 1 && c % 2 == 0)
char_fill(map, '.', s, c);
if (s > 1 && c % 2 == 1)
char_fill(map, ' ', s, c);
if (s == 10 && c == 18)
char_fill(map, '\0', s, c);
if (s > 1 && c == 0) {
char_fill(map, my_int_to_char(map -> lines), 0, 0);
map -> lines += 1;
}
if (!cmap[s][c]) {
puts("error filling the map, please try again.");
return (EXIT_FAILURE);
}
return 0;
}
map_data *map_gen(size_t lines, size_t letters, size_t width, size_t height)
{
map_data *map = malloc(sizeof(*map) + width * height * sizeof(map -> map[0]));
if(map)
{
map -> width = width;
map -> lines = lines;
map -> letters = letters;
map -> height = height;
for (size_t s = 0; s < height ; s++)
{
for (size_t c = 0; c < width; c++)
{
map_fill(map, s, c);
}
}
}
return (map);
}
At least this issue:
sizeof((char)18 * 10) is the sizeof an int, likely 4.
Allocate to the size of the referenced object times the number needed.
// char **map = malloc(sizeof((char)18 * 10));
char **map = malloc(sizeof *map * map_data.height);
Then allocate for each row
// Note <, not <=
for (int row = 0; row < map_data.height; row++) {
map[row] = malloc(sizeof *(map[row]) * map_data.width);
for (int col = 0; col < map_data.width; col++) {
map_fill(map, map_data, row, col);
}
}
Robust code would also check for allocation failures.

Getting a segmentation fault (core dumped) error when searching through my 2D array

I am working on a piece of code where a robot recursively searches through a maze to find the correct path to the end. I believe I have properly implemented the recursive function, however when I try to fill the 2D array in my main function I run into the following error:
Segmentation Fault (core dumped). I have shown my code below. Any help I could get would be helpful. Thank you!
#include <stdio.h>
#include <string.h>
int isValid(int x, int y)
{
if(x >= 0 && x <= 6 && y >=0 && y <= 6)
{
return 1;
}
return 0;
}
int mazeGo(char maze[6][6], char solution[6][6], int x, int y)
{
char mazeFull [6][6] =
{
{'.','#','#','#','#','#'},
{'.','.','.','.','.','#'},
{'#','.','#','#','#','#'},
{'#','.','#','#','#','#'},
{'.','.','.','#','.','.'},
{'#','#','.','.','.','#'}
};
//checks to sse if the robot is at the goal
if(x == 5 && y == 4 && isValid(x,y) == 1)
{
printf("Maze had been Solved");
solution[x][y] = '.';
return 1;
}
else if(x != 5 && y != 4 && isValid(x,y) == 1)
{
//Robot travels north
if(mazeGo(mazeFull,solution,x,y-1) == 1)
{
solution[x][y] = '.';
return 1;
}
//Robot travels East
else if(mazeGo(mazeFull,solution,x+1,y) == 1)
{
solution[x][y] = '.';
return 1;
}
//Robot travels south
else if(mazeGo(mazeFull,solution,x,y+1) == 1)
{
solution[x][y] = '.';
return 1;
}
//Robot travels west
else if(mazeGo(mazeFull,solution,x-1,y) == 1)
{
solution[x][y] = '.';
return 1;
}
else
{
solution[x][y] = '#';
return 0;
}
}
return 0;
}
int main()
{
int x = 0;
int y = 0;
char solution[6][6];
char maze [6][6] =
{
{'.','#','#','#','#','#'},
{'.','.','.','.','.','#'},
{'#','.','#','#','#','#'},
{'#','.','#','#','#','#'},
{'.','.','.','#','.','.'},
{'#','#','.','.','.','#'}
};
if(mazeGo(maze,solution,x,y) == 1)
{
for(int r = 0; r < 6; r++)
{
for(int c = 0; c < 6; c++)
{
printf("%c \n", solution[r][c]);
}
}
}
/*else
{
printf("There is no solution");
}*/
return 0;
}
Your maze is an array of 6x6 that means the positions to elements are located in [0][0] to [5][5].
Your isValid function have a bug when it let x and y be equal to 6. Try the change bellow:
int isValid(int x, int y) {
return (x >= 0 && x < 6 && y >= 0 && y < 6);
}

Reverse Polish converter

I am trying to make a reverse Polish printer which can perform the following operation-
Inputs:
(a+(b*c))
((a+b)*(z+x))
((a+t)*((b+(a+c))^(c+d)))
Outputs:
abc*+
ab+zx+*
at+bac++cd+^*
This is my code:
#include <stdio.h>
#include <string.h>
char pop(int t);
void push(int c, int t);
int main()
{
int z;
scanf("%d", &z);
char *a[100];
int i = 0;
int q = z;
while (q-- > 0)
{
char v[400];
scanf("%s", &v);
int t;
for (t = 0; t < strlen(v); t++) //loop to put the values and signs in the 2 stacks
{
if ((v[t] == '*') || (v[t] == '+') || (v[t] == '-') || (v[t] == '^'))
{
push(v[t], 2);
}
else if (v[t] == ')')
{
int y = pop(2);
push(y, 1);
}
else
{
push(v[t], 1);
}
}
int k = 0;
char c;
while ((c = pop(1)) !='\0') //loop to put elements in the array v
{
if (c != '(')
{
v[k++] = c;
}
}
v[k--] = '\0';
int m;
for (m=0; m != k; m++, k--) //for reversing the string
{
char t = v[m];
v[m] = v[k];
v[k] = t;
}
a[i++] =v;
printf("%s",a[i - 1]);
}
int p;
for (p = 0; p <z ; p++) //printing the elements
printf("%s\n",*a[p]);
return 0;
}
char ac[400];
char as[400];
int ic = 0;
int is = 0;
void push(int c,int t)
{
if (t == 1 && ic != 400)
ac[ic++] = c;
else if (t == 2 && is != 400)
as[is++] = c;
}
char pop(int t)
{
if (t == 1 && ic != 0)
return ac[--ic];
if (t == 2 && is != 0)
return as[--is];
return '\0';
}
But it is not even inputting properly and I am not able to figure out what are the mistakes in this code.Please help to figure out what are the problems.
after inputing the no of test cases i.e.int z and first line if input
it crashes
This is due to the
printf("%s\n",*a[p]);
as BLUEPIXY noticed, *a[p] is a char; but %s expects a char *, thus you need
printf("%s\n", a[p]);
and regarding v is out of scope, the crucial factor is not the scope (visibility), but the storage duration (lifetime) of v - its lifetime ends when execution of the block with which it is associated ends, and the value of a pointer a[i] to it becomes indeterminate; by changing
a[i++] =v;
to
a[i++] = strdup(v);
you can remedy that.

Why I am getting a SIGSEGV error for this program?

I am trying to make a reverse Polish printer on an online coding website which can perform the following operation-
Inputs:
(a+(b*c))
((a+b)*(z+x))
((a+t)*((b+(a+c))^(c+d)))
Outputs:
abc*+
ab+zx+*
at+bac++cd+^*
This is my code:
#include <stdio.h>
#include <string.h>
char pop(int t);
void push(int c, int t);
char a[100][400];
int main()
{
int z;
scanf("%d", &z);
int i = 0;
int q = z;
while (q-- > 0)
{
scanf("%s",&a[i][0]);
int t;
for (t = 0; t < strlen(a[i]); t++) //loop to put the values and signs in the 2 stacks
{
if ((a[i][t] == '*') || (a[i][t] == '+') || (a[i][t] == '-') || (a[i][t] == '^'))
{
push(a[i][t], 2);
}
else if (a[i][t] == ')')
{
int y = pop(2);
push(y, 1);
}
else
{
push(a[i][t], 1);
}
}
int k = 0;
char c;
while ((c = pop(1)) !='\0') //loop to put elements in the array v
{
if (c != '(')
{
a[i][k++] = c;
}
}
a[i][k--] = '\0';
int m;
for (m=0; m != k; m++, k--)
{
char t = a[i][m];
a[i][m] = a[i][k];
a[i][k] = t;
}
}
int p;
for (p = 0; p <z ; p++)
printf("%s\n",a[i]);
return 0;
}
char ac[400];
char as[400];
int ic = 0;
int is = 0;
void push(int c,int t)
{
if (t == 1 && ic != 400)
ac[ic++] = c;
else if (t == 2 && is != 400)
as[is++] = c;
}
char pop(int t)
{
if (t == 1 && ic != 0)
return ac[--ic];
if (t == 2 && is != 0)
return as[--is];
return '\0';
}
On compiling this code I am getting a SIGSEGV error.I don't know whats the mistake in this code.Please help
I don't know why you are getting SIGSEGV. However, I see couple of errors in your code.
You are using scanf("%s",&a[i][0]); but i is never changed from its initial value of 0. I suggest changing
while (q-- > 0)
to
for ( i = 0; i < z; ++i )
You are printing a[i] even though you are using p as the for loop index in
for (p = 0; p <z ; p++)
printf("%s\n",a[i]);
That's easily fixed by changing the second line to:
printf("%s\n",a[p]);
In your input, you didn't include the value of z. I hope that is an error in creating the post and that you have the value of z in your input.
With those changes, I don't see any problem in my environment. I tested using gcc 4.7.3. Not sure fixing those will fix the problem in your environment.

Resources