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.
Related
# include <stdio.h>
int main(){
int a,b;
scanf("%d %d",&a,&b);
while (a > 0) {
int digit = a % 10;
//printf("%d ",digit); for testing
a = a - digit;
a /= 10;
}
while (b > 0) {
int digit = b % 10;
//printf("%d ",digit); for testing
b = b - digit;
b /= 10;
}
}
This code takes two integers with the same lengths(a,b), splits them into their characters, now the question is how to print it like this for example(a=123 , b= 798 --> result = 17-29-38
Save the digits in arrays. Then you can loop over the arrays to print the digits at the end.
Also, you don't need to subtract digit before dividing by 10, since division discards the remainder.
# include <stdio.h>
#define MAXDIGITS 20
int main(){
int a,b;
int adigits[MAXDIGITS], bdigits[MAXDIGITS];
int digits = 0;
scanf("%d %d",&a,&b);
while (a > 0) {
int digit = a % 10;
//printf("%d ",digit); for testing
adigits[digits++] = digit;
a /= 10;
}
digits = 0;
while (b > 0) {
int digit = b % 10;
//printf("%d ",digit); for testing
bdigits[digits++] = digit;
b /= 10;
}
while (--digits >= 0) {
printf("%d%d", adigits[digits], bdigits[digits]);
if (digits != 0) {
putchar('-');
}
}
putchar('\n');
}
Your input is strings, and there is no point in converting those strings to integers just to change them back. Just work on the data directly. eg:
#include <stdio.h>
#include <stddef.h>
#include <ctype.h>
#include <stdlib.h>
struct buffer {
char *start;
char *end;
size_t cap;
};
void push(int c, struct buffer *);
int pop(struct buffer *);
void * xrealloc(void *buf, size_t num, size_t siz, void *offsetp);
int
main(void)
{
struct buffer a = {0};
struct buffer b = {0};
int c;
while( (c = getchar()) != EOF && !isspace(c) ) {
push(c, &a);
}
while(isspace(c = getchar())) {
;
}
ungetc(c, stdin);
while( (c = getchar()) != EOF ) {
push(c, &b);
}
while( (c = pop(&a)) != EOF ) {
putchar(c);
if( (c = pop(&b)) != EOF ) {
putchar(c);
}
}
while( (c = pop(&b)) != EOF ) {
putchar(c);
}
return 0;
}
int
pop(struct buffer *a)
{
return (a->start < a->end) ? *a->start++ : EOF;
}
void
push(int c, struct buffer *b)
{
if( b->start == NULL ) {
b->end = b->start = xrealloc(NULL, b->cap = 8, 1, NULL);
} else if( b->end >= b->start + b->cap ) {
b->start = xrealloc(b->start, b->cap *= 2, 1, &b->end);
}
*b->end++ = c;
}
void *
xrealloc(void *buf, size_t num, size_t siz, void *offsetp)
{
ptrdiff_t offset;
void **iterator = offsetp;
if( iterator != NULL ) {
offset = *iterator - buf;
}
buf = realloc(buf, num * siz);
if( buf == NULL ) {
perror("realloc");
exit(EXIT_FAILURE);
}
if( iterator != NULL ) {
*iterator = buf + offset;
}
return buf;
}
I would like to fit a string into multiple rows of a fixed width. I managed to separate the string into different rows so that their length will not pass the fixed width, but the problem is that some rows are not width (80) characters long, this is why I am trying to distribute the extra_space by adding spaces between words.
#include <stdio.h>
#include <string.h>
#include "stringdefault.h"
#include <conio.h>
#include <stdlib.h>
int main(){
int width = 80;
char s1[10000];
char substring[100] = " ";
char space = ' ';
gets(s1);
removeSpaces(s1);
char *base,*right_margin;
int extraSpace, numWords, numSpaces, incrementEachSpaceby, ind1, ind2, k;
int length;
length = string_length(s1);
base = s1;
for(int i = 0; i < width; i++)
{
printf("%d", i%10);
}
printf("\n");
while(*base)
{
if(length <= width)
{
puts(base); // display string
return(0); //and leave
}
right_margin = base+width;
while(!isspace(*right_margin))
{
right_margin--;
if( right_margin == base)
{
right_margin += width;
while(!isspace(*right_margin))
{
if( *right_margin == '\0')
break;
right_margin++;
}
}
}
*right_margin = '\0';
if(string_length(base) < width)
{
char *newStr = malloc(width);
extraSpace = width - string_length(base);
numWords = numberOfWords(base);
numSpaces = numWords - 1;
incrementEachSpaceby = extraSpace/numSpaces;
ind1 = 0;
ind2 = 0;
while (ind2 < width)
{
newStr[ind2] = base[ind1];
ind1++;
ind2++;
}
for(int i = 0; newStr[i]!='\0'; i++)
if((isspace(newStr[i])))
{
if(extraSpace > 0)
k = extraSpace;
else
k = 1;
while(k)
{
insert_substring(newStr, substring, i);
k--;
}
}
puts(newStr);
}
else
puts(base);
length -= right_margin-base+1; // +1 for the space
base = right_margin+1;
}
return 0;
}
stringdefault.h
int string_length(char s[])
{
int length = 0;
for(int i=0; s[i]!='\0'; i++)
length++;
return length;
}
char *substring(char *string, int position, int length)
{
char *pointer;
int c;
pointer = malloc(length+1);
if( pointer == NULL )
exit(EXIT_FAILURE);
for( c = 0 ; c < length ; c++ )
*(pointer+c) = *((string+position-1)+c);
*(pointer+c) = '\0';
return pointer;
}
void insert_substring(char *a, char *b, int position)
{
char *f, *e;
int length;
length = strlen(a);
f = substring(a, 1, position - 1 );
e = substring(a, position, length-position+1);
strcpy(a, "");
strcat(a, f);
free(f);
strcat(a, b);
strcat(a, e);
free(e);
}
char *removeSpaces(char *str)
{
int ip_ind = 0;
char *ptr;
while(*(str + ip_ind))
{
if ( (*(str + ip_ind) == *(str + ip_ind + 1)) && (*(str + ip_ind)==' ') )
{
ptr = str + ip_ind+1;
do{
*(ptr-1) = *ptr;
}while(*ptr++ != '\0');
}
else
ip_ind++;
}
*(str + ip_ind) = '\0';
return str;
}
The output that I get without the while loop inside the if statement
It seems that the newStr set of characters, contains spaces before it's first character.
I was assigned with a task of completing an assignment in C, without being taught C. (I have been learning Java) I am not sure how to fix this error nor do I know what the error means.
#include <stdio.h>
//int mystrcmp(char * s, char * t);
int main(int argc, char * argv[])
{
// #1 Prints out cmd line arguments
int i;
for (i = 0; i < argc; ++i)
{
printf("%s\n",argv[i]);
}
printf("\n"); //Spaceholder
// #2 String Compare
printf("%s %s\n", argv[1], argv[2]);
printf("Returned Value: %d\n", mystrcmp(argv[1], argv[2]));
//mystrcmp(argv[1],argv[2]);
// #3 String Concatenate
printf("\n"); //Spaceholder
printf("String Concatenate: %s\n", mystrcat(argv[1]));
// #4 String Copy
printf("\n"); //Spaceholder
// printf("String Copy: %s\n" , mystrcpy(argv[1]));
}
///////////
//Methods//
///////////
/* srtcmp: return < 0 if s < t, 0 if s==t, > 0 if s > t */
int mystrcmp(char * s, char * t)
{
int i;
for(i = 0; s[i] && s[2]; ++i)
{
if (s[i] == t[i] || (s[i]) == t[i])
continue;
else
break;
}
if (s[i] == t[i])
return 0;
if ((s[i]) < (t[i]))
return -1;
return 1;
}
mystrcat(char *dest, char *source)
{
int a = 0;
while(*(dest + a) != '\0')
{
a++;
}
int b = 0;
while(*(source + a) != '\0')
{
*(dest + a) = *(source + b);
a++;
b++;
}
}
mystrcpy(char * s, char * dest)
{
while((*s++ = *dest++)!= '\0')
;
return *dest;
}
I am assuming the error is coming from my mystrcat.
while(*(source + a) != '\0')
should be
while(*(source + b) != '\0')
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.
I'm trying to make a function that gets a string and a number from the user and then makes every words length the same as the number i got form the user and prints the new string.
for example :
abcd__efgh_i
number = 3
and i should get
abc_def_ghi
#include < stdio.h >
void f(char * p, int n) {
int i = 0, br = 0, d, m = 0, br1 = 0, g;
while (p[i] != '\0') {
if (p[i] != '\0') {
br++;
}
i++;
}
if (br % n == 0) {
d = (br / n) - 1;
} else {
d = (br / n);
}
g = br + d;
char b[g];
i = 0;
while (p[i] == '\0') {
if (p[i] == '\0') {
while (p[i] == '\0') {
i++;
}
} else {
b[m] = '\0';
m++;
br1 = 0;
}
b[m] = p[i];
m++;
i++;
br1++;
if (m == g) {
b[m] = '\0';
}
}
printf("%s", b);
}
#include <stdio.h>
void
shuffle (const char *str, unsigned int n) {
unsigned int i = 0;
// loop until the end of the string is found
while (*str) {
// Examine the current character. If it is not a space, output it
// and increment the number of characters output so far in the current word
if (*str != ' ') {
putchar (*str);
++i;
}
// Move to the next character
++str;
// Check if we have output "n" characters so far. If so, output a space to
// separate words and reset the character count
if (i == n) {
putchar (' ');
i = 0;
}
}
// Put a single new line at the end
putchar ('\n');
}
int
main () {
shuffle ("abcd efgh i jk", 3);
}
void f(const char * p, int n) {
char b[n+1];
int i=0;
while(*p){
if(*p == ' '){
++p;
continue;//skip
}
b[i++] = *p++;
if(i % n == 0){
b[i] = '\0';//move out from loop
printf("%s ", b);
i = 0;
}
}
printf("\n");
}