Related
i have to code a sudoku ocr for school in C.
I use an edge detection algorithm which returns a bmp file.
However, the returned file only shows 1/3 of the expected output.
Please can someone tell me what is wrong in my code :)
input image (BMP file)
output image (BMP file)
and here's my code :
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#define MAX_BRIGHTNESS 255
// C99 doesn't define M_PI (GNU-C99 does)
#define M_PI 3.14159265358979323846264338327
/*
* Loading part taken from
* http://www.vbforums.com/showthread.php?t=261522
* BMP info:
* http://en.wikipedia.org/wiki/BMP_file_format
*
* Note: the magic number has been removed from the bmpfile_header_t
* structure since it causes alignment problems
* bmpfile_magic_t should be written/read first
* followed by the
* bmpfile_header_t
* [this avoids compiler-specific alignment pragmas etc.]
*/
typedef struct {
uint8_t magic[2];
} bmpfile_magic_t;
typedef struct {
uint32_t filesz;
uint16_t creator1;
uint16_t creator2;
uint32_t bmp_offset;
} bmpfile_header_t;
typedef struct {
uint32_t header_sz;
int32_t width;
int32_t height;
uint16_t nplanes;
uint16_t bitspp;
uint32_t compress_type;
uint32_t bmp_bytesz;
int32_t hres;
int32_t vres;
uint32_t ncolors;
uint32_t nimpcolors;
} bitmap_info_header_t;
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t nothing;
} rgb_t;
// Use short int instead `unsigned char' so that we can
// store negative values.
typedef short int pixel_t;
pixel_t *load_bmp(const char *filename,
bitmap_info_header_t *bitmapInfoHeader)
{
FILE *filePtr = fopen(filename, "rb");
if (filePtr == NULL) {
perror("fopen()");
return NULL;
}
bmpfile_magic_t mag;
if (fread(&mag, sizeof(bmpfile_magic_t), 1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
// verify that this is a bmp file by check bitmap id
// warning: dereferencing type-punned pointer will break
// strict-aliasing rules [-Wstrict-aliasing]
if (*((uint16_t*)mag.magic) != 0x4D42) {
fprintf(stderr, "Not a BMP file: magic=%c%c\n",
mag.magic[0], mag.magic[1]);
fclose(filePtr);
return NULL;
}
bmpfile_header_t bitmapFileHeader; // our bitmap file header
// read the bitmap file header
if (fread(&bitmapFileHeader, sizeof(bmpfile_header_t),
1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
// read the bitmap info header
if (fread(bitmapInfoHeader, sizeof(bitmap_info_header_t),
1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
if (bitmapInfoHeader->compress_type != 0)
fprintf(stderr, "Warning, compression is not supported.\n");
// move file point to the beginning of bitmap data
if (fseek(filePtr, bitmapFileHeader.bmp_offset, SEEK_SET)) {
fclose(filePtr);
return NULL;
}
// allocate enough memory for the bitmap image data
pixel_t *bitmapImage = malloc(bitmapInfoHeader->bmp_bytesz *
sizeof(pixel_t));
// verify memory allocation
if (bitmapImage == NULL) {
fclose(filePtr);
return NULL;
}
// read in the bitmap image data
size_t pad, count=0;
unsigned char c;
pad = 4*ceil(bitmapInfoHeader->bitspp*bitmapInfoHeader->width/32.) - bitmapInfoHeader->width;
for(size_t i=0; i<bitmapInfoHeader->height; i++){
for(size_t j=0; j<bitmapInfoHeader->width; j++){
if (fread(&c, sizeof(unsigned char), 1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
bitmapImage[count++] = (pixel_t) c;
}
fseek(filePtr, pad, SEEK_CUR);
}
// If we were using unsigned char as pixel_t, then:
// fread(bitmapImage, 1, bitmapInfoHeader->bmp_bytesz, filePtr);
// close file and return bitmap image data
fclose(filePtr);
return bitmapImage;
}
// Return: true on error.
bool save_bmp(const char *filename, const bitmap_info_header_t *bmp_ih,
const pixel_t *data)
{
FILE* filePtr = fopen(filename, "wb");
if (filePtr == NULL)
return true;
bmpfile_magic_t mag = {{0x42, 0x4d}};
if (fwrite(&mag, sizeof(bmpfile_magic_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
const uint32_t offset = sizeof(bmpfile_magic_t) +
sizeof(bmpfile_header_t) +
sizeof(bitmap_info_header_t) +
((1U << bmp_ih->bitspp) * 4);
const bmpfile_header_t bmp_fh = {
.filesz = offset + bmp_ih->bmp_bytesz,
.creator1 = 0,
.creator2 = 0,
.bmp_offset = offset
};
if (fwrite(&bmp_fh, sizeof(bmpfile_header_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
if (fwrite(bmp_ih, sizeof(bitmap_info_header_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
// Palette
for (size_t i = 0; i < (1U << bmp_ih->bitspp); i++) {
const rgb_t color = {(uint8_t)i, (uint8_t)i, (uint8_t)i};
if (fwrite(&color, sizeof(rgb_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
}
// We use int instead of uchar, so we can't write img
// in 1 call any more.
// fwrite(data, 1, bmp_ih->bmp_bytesz, filePtr);
// Padding: http://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage
size_t pad = 4*ceil(bmp_ih->bitspp*bmp_ih->width/32.) - bmp_ih->width;
unsigned char c;
for(size_t i=0; i < bmp_ih->height; i++) {
for(size_t j=0; j < bmp_ih->width; j++) {
c = (unsigned char) data[j + bmp_ih->width*i];
if (fwrite(&c, sizeof(char), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
}
c = 0;
for(size_t j=0; j<pad; j++)
if (fwrite(&c, sizeof(char), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
}
fclose(filePtr);
return false;
}
// if normalize is true, map pixels to range 0..MAX_BRIGHTNESS
void convolution(const pixel_t *in, pixel_t *out, const float *kernel,
const int nx, const int ny, const int kn,
const bool normalize)
{
assert(kn % 2 == 1);
assert(nx > kn && ny > kn);
const int khalf = kn / 2;
float min = FLT_MAX, max = -FLT_MAX;
if (normalize)
for (int m = khalf; m < nx - khalf; m++)
for (int n = khalf; n < ny - khalf; n++) {
float pixel = 0.0;
size_t c = 0;
for (int j = -khalf; j <= khalf; j++)
for (int i = -khalf; i <= khalf; i++) {
pixel += in[(n - j) * nx + m - i] * kernel[c];
c++;
}
if (pixel < min)
min = pixel;
if (pixel > max)
max = pixel;
}
for (int m = khalf; m < nx - khalf; m++)
for (int n = khalf; n < ny - khalf; n++) {
float pixel = 0.0;
size_t c = 0;
for (int j = -khalf; j <= khalf; j++)
for (int i = -khalf; i <= khalf; i++) {
pixel += in[(n - j) * nx + m - i] * kernel[c];
c++;
}
if (normalize)
pixel = MAX_BRIGHTNESS * (pixel - min) / (max - min);
out[n * nx + m] = (pixel_t)pixel;
}
}
/*
* gaussianFilter:
* http://www.songho.ca/dsp/cannyedge/cannyedge.html
* determine size of kernel (odd #)
* 0.0 <= sigma < 0.5 : 3
* 0.5 <= sigma < 1.0 : 5
* 1.0 <= sigma < 1.5 : 7
* 1.5 <= sigma < 2.0 : 9
* 2.0 <= sigma < 2.5 : 11
* 2.5 <= sigma < 3.0 : 13 ...
* kernelSize = 2 * int(2*sigma) + 3;
*/
void gaussian_filter(const pixel_t *in, pixel_t *out,
const int nx, const int ny, const float sigma)
{
const int n = 2 * (int)(2 * sigma) + 3;
const float mean = (float)floor(n / 2.0);
float kernel[n * n]; // variable length array
fprintf(stderr, "gaussian_filter: kernel size %d, sigma=%g\n",
n, sigma);
size_t c = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
kernel[c] = exp(-0.5 * (pow((i - mean) / sigma, 2.0) +
pow((j - mean) / sigma, 2.0)))
/ (2 * M_PI * sigma * sigma);
c++;
}
convolution(in, out, kernel, nx, ny, n, true);
}
/*
* Links:
* http://en.wikipedia.org/wiki/Canny_edge_detector
* http://www.tomgibara.com/computer-vision/CannyEdgeDetector.java
* http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
* http://www.songho.ca/dsp/cannyedge/cannyedge.html
*
* Note: T1 and T2 are lower and upper thresholds.
*/
pixel_t *canny_edge_detection(const pixel_t *in,
const bitmap_info_header_t *bmp_ih,
const int tmin, const int tmax,
const float sigma)
{
const int nx = bmp_ih->width;
const int ny = bmp_ih->height;
pixel_t *G = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *after_Gx = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *after_Gy = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *nms = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *out = malloc(bmp_ih->bmp_bytesz * sizeof(pixel_t));
if (G == NULL || after_Gx == NULL || after_Gy == NULL ||
nms == NULL || out == NULL) {
fprintf(stderr, "canny_edge_detection:"
" Failed memory allocation(s).\n");
exit(1);
}
gaussian_filter(in, out, nx, ny, sigma);
const float Gx[] = {-1, 0, 1,
-2, 0, 2,
-1, 0, 1};
convolution(out, after_Gx, Gx, nx, ny, 3, false);
const float Gy[] = { 1, 2, 1,
0, 0, 0,
-1,-2,-1};
convolution(out, after_Gy, Gy, nx, ny, 3, false);
for (int i = 1; i < nx - 1; i++)
for (int j = 1; j < ny - 1; j++) {
const int c = i + nx * j;
// G[c] = abs(after_Gx[c]) + abs(after_Gy[c]);
G[c] = (pixel_t)hypot(after_Gx[c], after_Gy[c]);
}
// Non-maximum suppression, straightforward implementation.
for (int i = 1; i < nx - 1; i++)
for (int j = 1; j < ny - 1; j++) {
const int c = i + nx * j;
const int nn = c - nx;
const int ss = c + nx;
const int ww = c + 1;
const int ee = c - 1;
const int nw = nn + 1;
const int ne = nn - 1;
const int sw = ss + 1;
const int se = ss - 1;
const float dir = (float)(fmod(atan2(after_Gy[c],
after_Gx[c]) + M_PI,
M_PI) / M_PI) * 8;
if (((dir <= 1 || dir > 7) && G[c] > G[ee] &&
G[c] > G[ww]) || // 0 deg
((dir > 1 && dir <= 3) && G[c] > G[nw] &&
G[c] > G[se]) || // 45 deg
((dir > 3 && dir <= 5) && G[c] > G[nn] &&
G[c] > G[ss]) || // 90 deg
((dir > 5 && dir <= 7) && G[c] > G[ne] &&
G[c] > G[sw])) // 135 deg
nms[c] = G[c];
else
nms[c] = 0;
}
// Reuse array
// used as a stack. nx*ny/2 elements should be enough.
int *edges = (int*) after_Gy;
memset(out, 0, sizeof(pixel_t) * nx * ny);
memset(edges, 0, sizeof(pixel_t) * nx * ny);
// Tracing edges with hysteresis . Non-recursive implementation.
size_t c = 1;
for (int j = 1; j < ny - 1; j++)
for (int i = 1; i < nx - 1; i++) {
if (nms[c] >= tmax && out[c] == 0) { // trace edges
out[c] = MAX_BRIGHTNESS;
int nedges = 1;
edges[0] = c;
do {
nedges--;
const int t = edges[nedges];
int nbs[8]; // neighbours
nbs[0] = t - nx; // nn
nbs[1] = t + nx; // ss
nbs[2] = t + 1; // ww
nbs[3] = t - 1; // ee
nbs[4] = nbs[0] + 1; // nw
nbs[5] = nbs[0] - 1; // ne
nbs[6] = nbs[1] + 1; // sw
nbs[7] = nbs[1] - 1; // se
for (int k = 0; k < 8; k++)
if (nms[nbs[k]] >= tmin && out[nbs[k]] == 0) {
out[nbs[k]] = MAX_BRIGHTNESS;
edges[nedges] = nbs[k];
nedges++;
}
} while (nedges > 0);
}
c++;
}
free(after_Gx);
free(after_Gy);
free(G);
free(nms);
return out;
}
int main(const int argc, const char ** const argv)
{
if (argc < 2) {
printf("Usage: %s image.bmp\n", argv[0]);
return 1;
}
static bitmap_info_header_t ih;
const pixel_t *in_bitmap_data = load_bmp(argv[1], &ih);
if (in_bitmap_data == NULL) {
fprintf(stderr, "main: BMP image not loaded.\n");
return 1;
}
printf("Info: %d x %d x %d\n", ih.width, ih.height, ih.bitspp);
const pixel_t *out_bitmap_data =
canny_edge_detection(in_bitmap_data, &ih, 45, 50, 1.0f);
if (out_bitmap_data == NULL) {
fprintf(stderr, "main: failed canny_edge_detection.\n");
return 1;
}
if (save_bmp("out.bmp", &ih, out_bitmap_data)) {
fprintf(stderr, "main: BMP image not saved.\n");
return 1;
}
free((pixel_t*)in_bitmap_data);
free((pixel_t*)out_bitmap_data);
return 0;
}
This isn't really an answer, but I wanted to post the image I obtained from the code.
I took two actions on the .jpg posted a) reduce to 256 colours, b) save as 8-bit .bmp, done with an image editor.
Then after running the code I converted the 8-bit .bmp output to .png to post here.
I only changed one thing for MSVC, the VLA
//float kernel[n * n]; // variable length array
float *kernel = malloc(n * n * sizeof (float));
with free(kernel) at the end of the function. Although there were still several compiler warnings, they didn't seem to be material here, but it's still worth fixing them.
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
int getCharNum(int a) { return a / (8 * sizeof(char)); }
int getBitNum(int a) { return a % (8 * sizeof(char)); }
int fromCharNum(int a) { return a * 8 * sizeof(char); }
int get2DimI(int a) { return getCharNum(a) / 187500; }
int get2DimJ(int a) { return getCharNum(a) % 187500; }
void rle_compress(char *src, char *dst, int ls, int *ld) {
uint8_t t[129];
int i, j = 0, k = 0, keep;
char out[187500];
t[0] = src[j];
while (j++ < ls) {
t[1] = src[j];
if (t[0] != t[1]) {
i = 1;
if (j < ls)
do
t[++i] = src[++j];
while (j < ls && i < 128 && t[i] != t[i - 1]);
if ((keep = t[i] == t[i - 1]))
--i;
out[k++] = (char)i;
t[0] = t[i];
if (!keep)
continue;
}
i = 2;
do
t[1] = src[++j];
while (++i < 130 && t[0] == t[1]);
out[k++] = i + 125;
out[k++] = t[0];
t[0] = t[1];
}
ld = &k;
dst = out;
}
void rle_extract(char *src, char *dst, int ls) {
int i, j, l = 0, k = 0, max;
char out[187500];
j = 0;
while (k + 2 < ls) {
i = src[k++]; //segfault
j = src[k++];
max = i + (i < 128 ? 1 : -126);
while (max--)
out[l++] = j;
}
dst = out;
return 0;
}
int main(void) {
int32_t n = 0;
scanf("%d", &n);
int32_t a[n];
int32_t b[] = { -1, -1, -1 };
char **count;
count = (char**)malloc(1000 * sizeof(char*));
int count_l[] = { [999] = 0 };
for (int i = 0; i < 1000; ++i) {
count[i] = (char*)malloc(187500 * sizeof(char));
char *temp = NULL;
rle_compress(count[i], temp, 187500, &count_l[i]);
free(count[i]);
count[i] = temp;
}
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
for (int i = 0; i < n; i++) {
char *src = count[get2DimI(a[i]) / 187500];
char dst[187500];
rle_extract(src, dst, count_l[i / 187500]);
dst[get2DimJ(a[i])] ^= 1 << (getBitNum(a[i]));
rle_compress(dst, count[get2DimI(a[i]) / 187500], 187500, &count_l[i]);
}
int32_t mv = 187500000 / (8 * sizeof(char));
int j = 0;
for (int i = 0; i < mv; i++) {
char *src = count[i / 187500];
char dst[187500];
rle_extract(src, dst, count_l[i / 187500]);
int32_t x = dst[i % 187500];
if (x == 0)
continue;
for (int k = 0; k < 8 * sizeof(char); k++) {
if ((x >> (k)) & 1) {
b[j++] = fromCharNum(i) + k;
}
}
//free(dst);
}
int m1 = min(b[0], min(b[1], b[2])),
m3 = max(b[0], max(b[1], b[2])),
m2 = b[0] + b[1] + b[2] - m1 - m3;
printf("%d %d %d", m1, m2, m3);
for (int i = 0; i < 1000; ++i)
free(count[i]);
free(count);
return 0;
}
How to fix this code?
I'm trying to compress byte array (which should compress greatly as n should be <=1500000 and numbers are from 0 to 1.5*10^9), but code gives me segfault on all testing inputs which I've tried. Without compress everything worked like a charm, but needed a lot of memory (and limits are 64MiB).
The code is obscure but there are some major problems:
void rle_extract(char *src, char *dst, int ls) does not take the output buffer from its caller, nor does it return a pointer to it: dst = out; just updates the argument value, not the caller's variable passed as an argument. Furthermore return 0; from a void function is incorrect too.
in any case, rle_extract should not return its local out buffer because it is only defined during the execution of the function and is discarded as soon as the function returns.
You should either pass the buffer as an argument or allocate it locally and return the pointer to the caller.
There might be other problems, there is no explanation for what the code is supposed to do.
Firstly, I am sorry for my English.
I am trying to read an integer array which represents some sparse matrix from a binary and I have to print this matrix.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20
//on this way i have written the matrix in the binary
typedef struct{
int lin,col;
double val;
}termen;
typedef struct{
int nl,nc,nn;
termen* term;
}sparse_matrix;
void afisare_mat(sparse_matrix m){
int i,j,k = 0;
for(i = 0; i < m.nl; i++){
for(j = 0; j < m.nc; j++){
if(i == m.term[k].lin && j == m.term[k].col){
printf("%3.2lf ",m.term[k].val);
k++;
}else{
printf("%d ",0);
}
}printf("\n");
}
}
int main(){
/*this is the code used for write in the binary file
//i tried to print these values and seems to be ok
sparse_matrix m1,m2,m3;
m1.term = malloc(2*sizeof(termen));
m1.nl = 3;
m1.nc = 3;
m1.nn = 2;
m1.term[0].lin = 0;
m1.term[0].col = 1;
m1.term[0].val = 3.2;
m1.term[1].lin = 1;
m1.term[1].col = 2;
m1.term[1].val = 5.6;
afisare_mat(m1);
m2.term = malloc(3*sizeof(termen));
m2.nl = 4;
m2.nc = 4;
m2.nn = 3;
m2.term[0].lin = 0;
m2.term[0].col = 0;
m2.term[0].val = 1.9;
m2.term[1].lin = 1;
m2.term[1].col = 2;
m2.term[1].val = 0.5;
m2.term[2].lin = 2;
m2.term[2].col = 3;
m2.term[2].val = 6.960;
afisare_mat(m2);
m3.term = malloc(1*sizeof(termen));
m3.nl = 3;
m3.nc = 3;
m3.nn = 1;
m3.term[0].lin = 1;
m3.term[0].col = 2;
m3.term[0].val = 6.75;7
afisare_mat(m3);
FILE *f = fopen("in.bin","wb");
fwrite(&m1,sizeof(sparse_matrix),1,f);
fwrite(&m2,sizeof(sparse_matrix),1,f);
fwrite(&m3,sizeof(sparse_matrix),1,f);
fclose(f);
*/
FILE *f = fopen("in.bin","rb");
int n, v[10], i, j, k,nr = 0,it; //n=number of matrix asked, v=array with
//number(s)(<= n) of matrix which have to print
scanf("%d",&n);
sparse_matrix m;
while(fread(&k,sizeof(int),1,f) > 0){
fseek(f,2*sizeof(int),SEEK_CUR);
fseek(f,sizeof(termen*),SEEK_CUR);
nr++;
}
for(i = 0; i < n; i++){
scanf("%d",&v[i]);
if(v[i] > nr)
printf("That matrix not exist\n");
}
fseek(f,0,0);
j = 0;
while(fread(&k,sizeof(int),1,f) > 0){ //citesc nl din fiecare matrice
for(i = 0; i < n; i++){
if(j == v[i]){ //number of matrix which i read;
//print matrix
m.nl = k;
fread(&m.nc,sizeof(int),1,f);
fread(&m.nn,sizeof(int),1,f);
m.term = malloc(m.nn*sizeof(termen));
fread(m.term,sizeof(termen),m.nn,f);
afisare_mat(m);
free(m.term);
fseek(f,(j+1)*sizeof(sparse_matrix),0);
}
}j++;
}
fclose(f);
return 0;
}
This code prints on my screen the form of matrix but full of zeroes. I think that the rest of the elements (!= 0) aren't read ok from the binary file. Can you help me, please?
I have an array called puzzle which consist of words/letters/random strings and I want to check if it has any of the same strings in another array called dictionary (the strings in dictionary are listed in alphabetical order)
So I believe my problem is the binary search in my program, I'm not entire sure how to work around it using strings. I tried to use some strcmp() but I don't think thats the way to go?
When the program runs, it gets no output. that there is no matches but there are.
here is my binary search function:
int binsearch(char **dictionary, char *puzzle) {
int start = 1; //excluded first string of dictionary array bc #
int end = listlength;
while (start < end) {
int mid = (start + end) / 2;
int temp = strcmp(dictionary[mid], puzzle);
if (temp < 0) {
start = mid + 1; //it is in upper half
} else
if (temp > 0) { //check lower half
end = mid;
} else
return 1; //found a match hopefully
}
return 0;
}
and my entire code is here if maybe something you need to see
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define listlength 149256
#define maxWordLen 19
char **getWords(int rows, int cols);
void freeArray(char **array, int rows);
char **makeGridArray(int rows, int cols);
int binsearch(char **dictionary, char *puzzle);
void wordSearch(char **dictionary, char **puzzle, int row, int col);
const int DX_SIZE = 8;
const int DX[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
const int DY[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
int main() {
//read in dictionary
int i, j, x = 0, numCases, gridRow, gridCol;
char **words = getWords(listlength, maxWordLen);
//Get number of cases.
printf("enter number of cases:\n");
scanf("%d", &numCases);
//process each case.
while (x < numCases) {
scanf("%d%d", &gridRow, &gridCol);
//make word search grid
char **grid = makeGridArray(gridRow + 1, gridCol);
/* for testing if grid is storing properly
for (i = 0; i < gridRow + 1; i++) {
printf("%s\n", grid[i]);
}
*/
printf("Words Found Grid #%d:\n", x + 1);
wordSearch(words, grid, gridRow + 1, gridCol);
x++;
freeArray(grid, gridRow + 1);
}
freeArray(words, listlength);
}
char **getWords(int rows, int cols) {
int i;
//allocate top level of pointers.
char **words = malloc(sizeof(char*) * rows);
//allocate each individual array
for (i = 0; i < rows; i++) {
words[i] = malloc(sizeof(char) * cols + 1);
}
//read dictionary.txt
FILE *dictionary = fopen("dictionary.txt", "r");
for (i = 0; i < rows; i++) {
fgets(words[i], cols + 1,dictionary);
}
fclose(dictionary);
return words;
}
char **makeGridArray(int rows, int cols) {
//allocate top level of pointers.
char **grid = malloc(sizeof(char*) * rows);
int i, j;
//allocate each individual array
for (i = 0; i < rows; i++) {
grid[i] = malloc(sizeof(char) * cols + 1);
}
//read in user input grid
for (i = 0; i < rows; i++) {
gets(grid[i]);
}
return grid;
}
int binsearch(char **dictionary, char *puzzle) {
int start = 1; //excluded first string of dictionary array bc #
int end = listlength;
while (start < end) {
int mid = (start + end) / 2;
int temp = strcmp(dictionary[mid], puzzle);
if (temp < 0) {
start = mid + 1; //it is in upper half
} else
if (temp > 0) { //check lower half
end = mid;
} else
return 1; //found a match hopefully
}
return 0;
}
void wordSearch(char **dictionary, char **puzzle, int row, int col) {
int i, X, Y, dir;
char wordsfound[19] = { '\0' };
for (X = 0; X < row + 1; X++) {
for (Y = 0; Y < col; Y++) {
for (dir = 0; dir < DX_SIZE; dir++) //check every direction
for (i = 0; i < 19; i++) {
//will continue in direction DX,DY starting at x,y
int nextX = X + DX[dir] * i;
int nextY = Y + DY[dir] * i;
if (nextX < 0 || nextX >= row) break; //keep in bounds
if (nextY < 0 || nextY >= col) break;
//store the string of letters to check
wordsfound[i] = (puzzle[nextX][nextY]);
if (i > 3) { //minimum word is 4
wordsfound[i + 1] = '\0';
//if the string of letters is actually a word, print
int bin = binsearch(dictionary, wordsfound);
if (bin) {
printf("%s\n", wordsfound);
}
}
}
}
}
return;
}
void freeArray(char **array, int rows) {
//free arrays
int i;
for (i = 0; i < rows; i++) {
free(array[i]);
}
free(array);
}
The problem is in the getwords() function: you read the words from the dictionary with fgets() but forget to remove the trailing \n. All words in the dictionary have a trailing \n, so none of them match your searches.
Here is a corrected version:
char **getWords(int rows, int cols) {
char line[256];
int i;
//allocate top level of pointers.
char **words = malloc(sizeof(char*) * rows);
//read dictionary.txt
FILE *dictionary = fopen("dictionary.txt", "r");
for (i = 0; i < rows; i++) {
if (!fgets(line, sizeof line, dictionary))
line[0] = '\0';
line[strcspn(line, "\n")] = '\0';
words[i] = strdup(line);
}
fclose(dictionary);
return words;
}
Note that it would be better not to rely on a known magical listlength. You could also ignore comment and empty lines while reading the dictionary.
I'm currently making a program for my school project. It's supposed to read a ppm image and return a gradient as an output. But I'm having a problem with large image such as 420 x 360. It works fine with image below 300 pixels on both side. Could anyone tell me what's wrong with my code? Thx. Oh and it's in C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct imageHeader{
char code[3];
char startComment;
char comment[1000];
int width;
int height;
int offset;
} header;
struct imagePixel{
int red;
int green;
int blue;
int total;
};
int main(){
FILE *image;
FILE *imageOut;
image = fopen("sunset.ppm", "rb");
imageOut = fopen("output.ppm", "wb");
fseek(image, 0, SEEK_SET);
fseek(imageOut, 0, SEEK_SET);
// ********* Get the right Code *************
fgets(header.code, sizeof(header.code), image);
if(strcmp(header.code, "P3")){
puts("Not suitable file format!");
}
fputs(header.code, imageOut);
fputs("\n", imageOut);
//*********** SKIP THE COMMENT IF EXIST *****************
header.startComment = fgetc(image);
if(header.startComment = '#'){
fgets(header.comment, sizeof(header.comment), image);
}
fputs(header.comment, imageOut);
//**************** Get the Width of the picture ***************
fscanf(image, "%d", &header.width);
fprintf(imageOut, "%d ", header.width);
//**************** Get the Height of the picture **************
fscanf(image, "%d", &header.height);
fprintf(imageOut, "%d\n", header.height);
//***************** Get the offset color of the picture ************
fscanf(image, "%d", &header.offset);
fprintf(imageOut, "%d\n", header.offset);
struct imagePixel *ptrOne;
ptrOne = (struct imagePixel*) malloc(sizeof(ptrOne) * header.height *header.width);
if (ptrOne == NULL){
printf("Error! Run out of memory!");
return 1;
}
struct imagePixel number[header.height][header.width];
//**************read the image*****************
for(int i = 0; i <= header.height - 1; i++){
for(int j = 0; j <= header.width - 1; j++){
fscanf(image, "%d", &number[i][j].red);
fscanf(image, "%d", &number[i][j].green);
fscanf(image, "%d", &number[i][j].blue);
number[i][j].total = (0.2126 * number[i][j].red) + (0.7152 * number[i][j].green) + (0.0722 * number[i][j].blue);
//number[i][j].total = (number[i][j].red) + (number[i][j].green) + (number[i][j].blue);
}
}
for(int i = 0; i <= header.height - 1; i++){
for(int j = 0; j <= header.width - 1; j++){
int axisXswap = i;
int axisYswap = j;
for(int x = i; x <= header.height - 1; x++){
for(int y = j; y <= header.width - 1; y++){
if(number[x][y].total > number[axisXswap][axisYswap].total){
axisXswap = x;
axisYswap = y;
}
}
}
struct imagePixel temp;
temp.red = number[i][j].red;
temp.green = number[i][j].green;
temp.blue = number[i][j].blue;
temp.total = number[i][j].total;
number[i][j].red = number[axisXswap][axisYswap].red;
number[i][j].green = number[axisXswap][axisYswap].green;
number[i][j].blue = number[axisXswap][axisYswap].blue;
number[i][j].total = number[axisXswap][axisYswap].total;
number[axisXswap][axisYswap].red = temp.red;
number[axisXswap][axisYswap].green = temp.green;
number[axisXswap][axisYswap].blue = temp.blue;
number[axisXswap][axisYswap].total = temp.total;
}
}
for(int i = 0; i <= header.height-1; i++){
for(int j = 0; j <= header.width-1; j++){
fprintf(imageOut, "%d %d %d\n", number[i][j].red, number[i][j].green, number[i][j].blue);
}
}
fclose(image);
fclose(imageOut);
}
Instead of allocating on the stack you should use the heap:
struct imagePixel **number; // two dimensional array of pixels
// allocate rows
number = malloc(sizeof(struct imagePixel *) * header.height);
for (i = 0; i < header.height; ++i) {
// allocate columns for each row
number[0] = malloc(sizeof(struct imagePixel) * header.width);
}
// do free() in reverse as above