So basically I have a struct Pixel:
struct Pixel {
int r;
int g;
int b;
} Pixel;
To store RGB values from a file like this:
0
240
233
2
234
42
Where each 3 values is the red, green and blue value respectively.
Now i've created an array of fixed width and height (I already know the image width and height), so here is the code I have so far:
#define WIDTH 640
#define HEIGHT 480
//new array of WIDTH rows, HEIGHT columns
struct Pixel *rgbArray[WIDTH][HEIGHT];
int x, y;
for(y = 0; y < HEIGHT; y++) {
for(x = 0; x < WIDTH; x++) {
struct Pixel *newPixel;
fscanf(fd, "%d\n%d\n%d\n", &newPixel->r, &newPixel->g, &newPixel->b);
rgbArray[x][y] = newPixel;
}
}
It crashes without error, can anyone help me figure out why? I hope it's not something simply stupid ;_;.
Thanks in advance
First problem
struct Pixel *newPixel;
is uninitialized and dereferencing it with the inderiction operator -> is undefined behavior which might explain your crash, you don't seem to need a pointer so
struct Pixel newPixel;
should be fine, and then
if (fscanf(fd, "%d%d%d", &newPixel.r, &newPixel.g, &newPixel.b) == 3)
rgbArray[x][y] = newPixel;
else
handle_error();
provided that
struct Pixel rgbArray[WIDTH][HEIGHT];
Related
I am new to programming in C so I have started making a simple project. I am having an issue with the below code, which seems to be something related to the way memory is managed in C but I'm not sure.
I have a 1280x720 array of Particles which I fill with zeros and with "none". Then I fill in a single entry at (1,1). Finally I print out all the 'particles' that are not "none". The strange behaviour comes from the fact that when I do this I get an output of:
721 0 sand 1 1 sand
Clearly the second value should be there, but the first should not. I have tried with different values of x,y and it always adds 720 to x, and subtracts 1 from y.
#include <stdio.h>
#include <string.h>
typedef struct {
char name[10];
int colour;
} Particle;
Particle particles[1280][720];
void main() {
//Fill in the 1280 x 720 array with 0's and None
for (int y=0; y<720; y++) {
for (int x=0; x<1280; x++) {
particles[y][x].colour = 0x000000;
strcpy(particles[y][x].name, "none");
}
}
//Copy in 1 pixel of sand
strcpy(particles[1][1].name, "sand");
particles[1][1].colour = 0xFFFF00;
//Print out all the pixels that are not none, which should
//just print out a single pixel at (1,1)
for (int y=0; y<720; y++) {
for (int x=0; x<1280; x++) {
if (strcmp("none",particles[y][x].name) != 0) {
printf("%d %d %s\n",x,y,particles[y][x].name);
}
}
}
}
Sorry if this is a simple question. Thanks in advance.
Each rows of the array particles have only 720 elements, so particles[y][x] is out-of-range when x >= 720. Accessing out-of-range element invokes undefined behavior.
Quote from N1570 J.2 Undefined behavior:
An array subscript is out of range, even if an object is apparently accessible with the
given subscript (as in the lvalue expression a[1][7] given the declaration int
a[4][5]) (6.5.6).
Allocate enough elements to avoid buffer overrun. It seems you should use
Particle particles[720][1280];
instead of
Particle particles[1280][720];
It is better to define the width and height as macro to avoid typo:
#include <stdio.h>
#include <string.h>
#define WIDTH 1280
#define HEIGHT 720
typedef struct {
char name[10];
int colour;
} Particle;
Particle particles[HEIGHT][WIDTH];
void main() {
//Fill in the WIDTH x HEIGHT array with 0's and None
for (int y=0; y<HEIGHT; y++) {
for (int x=0; x<WIDTH; x++) {
particles[y][x].colour = 0x000000;
strcpy(particles[y][x].name, "none");
}
}
//Copy in 1 pixel of sand
strcpy(particles[1][1].name, "sand");
particles[1][1].colour = 0xFFFF00;
//Print out all the pixels that are not none, which should
//just print out a single pixel at (1,1)
for (int y=0; y<HEIGHT; y++) {
for (int x=0; x<WIDTH; x++) {
if (strcmp("none",particles[y][x].name) != 0) {
printf("%d %d %s\n",x,y,particles[y][x].name);
}
}
}
}
I'm having issues filling a 2d array of a struct inside a struct. It allows me to do it for pixels[0][1], pixels[0][2]....etc. However, once I increase the first index i.e pixels[1][1], I get a bus error 10. Any help would be appreciated. I've cut out some code to make it more readable but if you require all of it let me know! What the program is doing is reading a PPM image and displaying the information, the trouble i'm having is storing the pixels of the image.
#define MAX_HEIGHT 4
#define MAX_WIDTH 4
typedef struct Pixel{
int red;
int green;
int blue;
}Pixel;
typedef struct PPM{
char code[2];
int width, height;
int max;
Pixel * pixels[MAX_HEIGHT][MAX_WIDTH];
}PPM;
struct PPM * getPPM(FILE * fd){
PPM * image = NULL;
image = malloc(sizeof(PPM));
//have got all the other PPM info here ask if needed
int i;
int j;
for(i = 0; i<MAX_HEIGHT-1; i++){
for(j = 0; j<MAX_WIDTH-1; j++){
// struct Pixel newPPM_Pixel;
if(fscanf(fd, "%d %d %d", &image->pixels[i][j]->red, &image->pixels[i][j]->green, &image->pixels[i][j]->blue) == 3){
//rgb_array[i][j] = newPPM_Pixel;
printf("/ %d / %d / %d", image->pixels[i][j]->red, image->pixels[i][j]->green, image->pixels[i][j]->blue);
}
}
}
return image;
}
Change line :
Pixel * pixels[MAX_HEIGHT][MAX_WIDTH];
to :
Pixel pixels[MAX_HEIGHT][MAX_WIDTH]; //without an asterisk
This is the way to declare a 2D array. If you want pixels to be a pointer, declare it like this :
Pixel **pixels;
and then dynamically allocate memory for it :
int i;
pixels = malloc (MAX_HEIGHT*sizeof(Pixel*));
if (pixels == NULL)
printf ("Error allocating memory\n");
for (i = 0; i < MAX_HEIGHT; i++)
pixels[i] = malloc(MAX_WIDTH*sizeof(Pixel));
if (pixels[i] == NULL)
printf ("Error allocating memory\n");
You can read more about 2D dynamic memory allocation here.
I have the following structure im using to encode a PPM file with a message using steganography:
typedef struct{
char code[CODE_LENGTH];
COMMENT *commentPPM;
int width, height, max;
COLOR (*colorValues)[];
} PPM;
and the color:
typedef struct{
unsigned char red, green, blue;
} COLOR;
and method:
PPM *encode(char *text, PPM *img){
//tested
printf("entered encode\n");
PPM *newPPM;
newPPM = duplicate(img);
printf("duplicated ppm\n");
int x,y, currentChar, textLength;
textLength = strlen(text);
////
for(currentChar = x = y = 0; currentChar < textLength; currentChar++){
printf("the current character is %c\n", *(text+currentChar));
//between 1 and the width
x += (rand() % (newPPM->width -1)) + 1;
printf("generated %d for x\n",x);
if(x >= newPPM->width){
printf("%d is greater than width(%d)\n",x,newPPM->width);
x -= newPPM->width;
printf("%d is the new x\n", x);
y++;
printf("incremented y to be %d\n", y);
}
newPPM->colorValues[y][x].red = text[currentChar]; //error (1)
printf("changed the value of color[%d][%d].red, to be %d, which is %c\n",y,x, text[currentChar], text[currentChar]);
}
return newPPM;
}
How do you access for example "red" within the pointer to the 1d array seen at (1)?
Edit: I get the error message:
"error: invalid use of array with unspecified bounds
newPPM->colorValues[y][x].red = text[currentChar];"
Edit 2: I'm hearing that I cannot access the elements of colorValues in
typedef struct{
char code[CODE_LENGTH];
COMMENT *commentPPM;
int width, height, max;
COLOR (*colorValues)[];
} PPM;
as it hasn't got the width specified so i cant determine the offset. However I this is just a pointer to a flexible array member is getting assigned a type
ppmFile->colorValues = getColors(fd, ppmFile->width, ppmFile->height);
COLOR (*getColors(FILE *fd, int width, int height))[]{
COLOR (*colors)[width] = (COLOR(*)[width]) malloc(sizeof(COLOR[height][width]));
int i,j;
for(i = 0; i < height; i++) {
for(j = 0; j < width; j++) {
fscanf(fd,"%d %d %d", &colors[i][j].red, &colors[i][j].green, &colors[i][j].blue);
}
}
return colors;
}
which has got the width specified. So if I'm understanding correct when I am passing this back to be stored in the struct i am "losing" the offset (width). However When I am in the encrypt method, I have access to the width, height, and current x and y positions, surely there is a way of telling the compiler that this flexible array member has the offset of width,I did do this in the printColors method and it worked fine (see bellow), why cant I tell the compiler that the values stored in newPPM->colorValues have the offset of width?
void printColors(int width, int height, COLOR (*colors)[width]){
int n, j;
for(n = 0; n < height; n++) {
for(j = 0; j < width; j++) {
printf("%d %d %d\n", colors[n][j].red, colors[n][j].green, colors[n][j].blue);
}
}
}
is there a way of casting the newPPM->colorValues to tell it to have the offset width? Like I did with colors in printColors
You're probably getting an error like:
prog.c:10:14: error: subscript of pointer to incomplete type 'struct foo []'
thing->foos[0][0].bar;
~~~~~~~~~~~^
1 error generated.
For reference, the above is the output of compiling this code:
struct foo { int bar; };
struct baz {
struct foo (*foos)[];
};
int main () {
struct baz * thing;
thing->foos[0][0].bar;
return 0;
}
(Live)
What the compiler is trying to tell you is that it cannot compute the offset needed to access subsequent elements of the outer array. The reason is that it doesn't know the size of the array elements (as they're of incomplete type, that is lacking size information).
Basically, it's trying to compute (the following is a pseudo language, not C)
thing + offset(foos) + 0 * sizeof(struct foo[]) + 0 * sizeof(struct foo) + offset(bar)
but it can't because it doesn't know sizeof(struct foo[]).
The root of this issue is that your trying to have a pointer to a variable length array in the first place. Changing the member to
struct foo (*foos)[42];
"solves" this by giving the arrays dome size.
If you want a 2D array just make it 1D, appending all inner arrays. (Of course this works only if they're of the same size, i.e. if you want a rectangular 2D array)
struct foo * grid = malloc (sizeof (struct foo) * rows * columns);
// access using grid [c * rows + r]
You can access 2D data in a 1D array by calculating the array index formula yourself.
buf[ width*y + x ];
where width needs to be the stride in units of the buffer type.
I am trying to flip an image in C vertically so if the image is < it will end up > and my function includes
//Setting the struct up for the pixel's
struct pixel
{
unsigned char red;
unsigned char green;
unsigned char blue;
};
//Setting the struct up for the Image Type and scanning in the pxiels into an array
struct ImageType
{
char ppImage[3];
char comment[256];
char newlinechar;
int width, height;
int maxColor = 255;
struct pixel image[100][100];
};
//Function in order to flip the image, going from the left most pixel flipping with the right most
void MirrorVertical(struct ImageType imgur)
{
int x,y;
const int middle = imgur.width / 2;
struct pixel tmp;
struct *pixel p;
for(y=0; y < imgur.height; ++y)
{
p = tmp + y * imgur.width;
for(x=0; x < middle; ++x)
{
tmp = p[x];
p[x] = p[imgur.width - 1 - x];
p[imgur.width - 1 - x] = tmp;
}
}
}
I got my structs to work but for some reason my function will not output it, I am scanning in the image into from a struct so....
//Scanning in the pixels for the first image
for(i=imageA.height-1; i <= 0; i--)
{
for(j=0; j < imageA.width; j++)
{
scanf("%hhu", &imageA.image[i][j].red);
scanf("%hhu", &imageA.image[i][j].green);
scanf("%hhu", &imageA.image[i][j].blue);
}
}
What am I doing wrong in my function?
It should be
for(x=0; x < width; x++)
{
for(y = 0; y < height/2; y++)
{
temp = imgur.image[x][y];
imgur.image[x][y] = imgur.image[x][height-y-1]
imgur.image[x][height-y-1] = temp;
}
}
}
Shouldn't this: for(i=imageA.height-1; i <= 0; i--) be for(i=imageA.height-1; i >= 0; i--)? (in the "scanning in the pixels for the first image" code)
I imagine your compiler must be complaining about
struct pixel tmp;
struct *pixel p;
for(y=0; y < imgur.height; ++y)
{
p = tmp + y * imgur.width;
You are adding a struct to an int and allocating the result to a pointer. How is it supposed to work?
EDIT now that you have updated your question with "better" code and it's still not working, here are a few things you could / should change.
You declare a variable tmp then try to access temp. Recipe for failure
You pass the entire struct imgur to the function. That means "make a copy of everything". You should really pass a pointer to the object - change the prototype to reflect that, and access the elements as imgur->height etc
You never declare the variables height and width in your MirrorVertical function
(minor) you compute the value height - 1 - y twice per inner loop - 20000 times in total. If you swap the inner and outer loops and compute it just once (and assign to a new variable newY) you can save a little bit of time (not sure it it's really more efficient since you end up looping over X which might destroy cache coherence instead, especially with big images).
My compiler (and the C standard) complains about the statement int maxColor = 256; in the definition of the struct; you cannot initialize a value in the typedef.
Miscellaneous other errors thrown by the compiler.
I took the liberty of fixing many of them - that leads to the following code which appears to compile and run; now all you need is add your "input image" and "output image" functions (maybe).
#include <stdio.h>
//Setting the struct up for the pixels
struct pixel
{
unsigned char red;
unsigned char green;
unsigned char blue;
};
//Setting the struct up for the Image Type and scanning in the pixels into an array
struct ImageType
{
char ppImage[3];
char comment[256];
char newlinechar;
int width;
int height;
int maxColor; // cannot initialize this here; removed "=256"
struct pixel image[100][100];
};
//Function in order to flip the image, going from the left most pixel flipping with the right most
void MirrorVertical(struct ImageType *imgur) // using a pointer to the struct
{
int x,y, height, width; // added declaration of height, width
// const int middle = imgur->width / 2; // removed, not used
struct pixel tmp; // use same name here and in loop
height = imgur->height; // initialize once - save a redirect later
width = imgur->width; // ditto
for(y = 0; y < imgur->height/2; y++) // made this the outer loop
{
int newY = height - y - 1; // so we only compute it once
for(x=0; x < imgur->width; x++)
{
tmp = imgur->image[x][y]; // use "tmp" not "temp"
imgur->image[x][y] = imgur->image[x][newY];
imgur->image[x][newY] = tmp;
}
}
}
// a simple main program… this doesn't really do anything except call the function
int main(void) {
struct ImageType i1;
// … need to add code to import the image
MirrorVertical(&i1); // note - passing POINTER to i1, not the entire struct
// … need to add code to export the image
}
Let me know if that works.
I am trying to pass a pointer rgb that is initialized with memset to 0 and then looped through to place a 32 bit integer only in the bounds that I create with height and width input (h and w) as well as offset from the top left corner of the 2d array (x and y). after compiling, I seem to have the value with printf of the pointer just after it was made which gives the correct value (in my case 0xFFFFFF with and input of 255 255 255 for r g b) but after it is passed through to rgb2yuv function, it is set to 0 when I printf there.
Any suggestions would be awesome!
#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
/*global definitions*/
#define WIDTH 480
#define HEIGHT 240
/*global declarations*/
int w,h,scrn, bytewrite;
unsigned char red, green, blue;
static unsigned long rgb[WIDTH][HEIGHT];
/*function declarations*/
void colorq();
void rgb_rectdraw(int x, int y, int w, int h, unsigned char red ,
unsigned char green, unsigned char blue, unsigned long *rgb);
void rgb2yuv(unsigned long *rgb);
/*
Function Name: main
Purpose: main function
*/
int main(int argc, char** argv){
printf("\n");
int x, y;
/*call colorq to create a 32bit number of RGB*/
colorq();
/ *call rgb_rectdraw to draw a rectangle RGB array*/
rgb_rectdraw(x, y, w, h, red, green, blue, rgb);
/*call rgb2yuv to take the RGB array and covert it to a YUV array*/
rgb2yuv(rgb);
return 0;
}
/*
Function name: color q
Purpose: asks user to input colors from 0 to 255 in RGB format
*/
void colorq(){
printf("Please enter a color for Red Green and Blue from 0 to 255:\n");
scanf("%hu", &red);
scanf("%hu", &green);
scanf("%hu", &blue);
printf("\n");
return;
}
/*
Function name: rectdraw
Purpose: Draws a rectangle array
*/
void rgb_rectdraw(int x, int y, int w, int h,unsigned char red,
unsigned char green, unsigned char blue,unsigned long *rgb){
unsigned long rgbpixel;
/* testing only take out when
finished debugging why red is always 0 after scanf */
red = 255;
printf("red set to 255 for debugging\n");
/*creates a 32-bit number of RGB*/
rgbpixel = (red<<16)|(green<<8)|blue;
printf("%#x\n",rgbpixel);
/*create array of width w height h*/
/*initialize array*/
memset (rgb, 0,sizeof(HEIGHT*WIDTH));
int i, j, startx, stopx, starty, stopy;
printf("enter width and height of rectangle in pixels\n");
scanf("%d %d", &w, &h);
printf("enter offset x pixels and y pixels of rectangle:\n");
scanf("%d %d", &x, &y);
startx=x;
starty=y;
stopx=x+w;
stopy=y+w;
/* creates array of w and h of int rgh */
for(i=startx; i <= stopx; i++){
for(j=starty; j <= stopy; j++){
rgb = rgbpixel;
}
j = 0;
}
printf("original rgb %#x\n",rgb);
return ;
}
/*
*Function Name: rgb2yuv
*Purpose: convert the RGB array to a YUV array
*/
void rgb2yuv(unsigned long *rgb){
int i,j;
printf("ptrpassed = %#x\n",*rgb);
for(i=0; i<=WIDTH;i++){
for(j=0; j<=HEIGHT; j++){
}
}
printf("\n");
return;
}
I went through and basically sorted out all the warts, and explained why. A lot of it amounts to the fact that if your compiler spits out warnings, you have to listen to them.
/* Changed: Code formatted for my sanity */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
/*global definitions*/
#define WIDTH 480
#define HEIGHT 240
/*global declarations*/
int w,h,scrn, bytewrite;
/* Changed: to a short because I don't like the fact that I might be overwriting
memory on accident (in colorq). */
unsigned short red, green, blue;
static unsigned long rgb[WIDTH][HEIGHT];
/* Changed: Some format strings have been changed to get rid of compiler
warnings. */
/*function declarations*/
void colorq();
/* Changed: Specify the second dimension when you're passing an array. */
void rgb_rectdraw(int x, int y, int w, int h, unsigned char red,
unsigned char green, unsigned char blue,
unsigned long rgb[][HEIGHT]);
/* Changed: always pass an array of arrays. */
void rgb2yuv(unsigned long rgb[][HEIGHT]);
/*
Function Name: main
Purpose: main function
*/
int main(int argc, char** argv)
{
printf("\n");
int x, y;
/*call colorq to create a 32bit number of RGB*/
colorq();
/* call rgb_rectdraw to draw a rectangle RGB array */
rgb_rectdraw(x, y, w, h, red, green, blue, rgb);
/* call rgb2yuv to take the RGB array and covert it to a YUV array */
rgb2yuv(rgb);
return 0;
}
/*
Function name: color q
Purpose: asks user to input colors from 0 to 255 in RGB format
*/
void colorq(){
/* Suggestion: restructure this method to just take in all its input
locally, then return a rgbpixel. */
printf("Please enter a color for Red Green and Blue from 0 to 255:\n");
scanf("%hu", &red);
scanf("%hu", &green);
scanf("%hu", &blue);
printf("\n");
return;
}
/*
Function name: rectdraw
Purpose: Draws a rectangle array
*/
void rgb_rectdraw(int x, int y, int w, int h,unsigned char red,
unsigned char green, unsigned char blue,
unsigned long rgb[][HEIGHT])
{
unsigned long rgbpixel;
/* testing only take out when
finished debugging why red is always 0 after scanf */
red = 255;
printf("red set to 255 for debugging\n");
/*creates a 32-bit number of RGB*/
/* Changed: Added the extra 0xFF masking because of shortness rather than
charness. */
rgbpixel = ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);
printf("%#lx\n",rgbpixel);
/*create array of width w height h*/
/*initialize array*/
/* Changed: fill the size of one element times the number of elements */
memset(rgb, 0, sizeof(unsigned long) * HEIGHT * WIDTH);
int i, j, startx, stopx, starty, stopy;
printf("enter width and height of rectangle in pixels\n");
scanf("%d %d", &w, &h);
printf("enter offset x pixels and y pixels of rectangle:\n");
scanf("%d %d", &x, &y);
startx=x;
starty=y;
stopx=x+w;
stopy=y+w;
/* creates array of w and h of int rgh */
for(i=startx; i <= stopx; i++){
for(j=starty; j <= stopy; j++){
rgb[i][j] = rgbpixel;
}
j = 0;
}
printf("original rgb %#lx\n", (long unsigned int) rgb);
return ;
}
/*
*Function Name: rgb2yuv
*Purpose: convert the RGB array to a YUV array
*/
void rgb2yuv(unsigned long rgb[][HEIGHT]){
int i,j;
/* Changed: You can't just dereference rgb twice -- you have to use array
notation here. */
printf("ptrpassed = %#lx\n", rgb[0][0]);
for(i=0; i<=WIDTH; i++){
for(j=0; j<=HEIGHT; j++){
}
}
printf("\n");
return;
}
This actually has a number of bugs, but your first issue is assigning the pixel value to the array:
for(i=startx; i <= stopx; i++){
for(j=starty; j <= stopy; j++){
rgb = rgbpixel;
}
j = 0;
}
You probably meant something like this:
rgb[i][j] = rgbpixel;
You don't need to reset j to 0 -- the inner for-loop will immediately reset j to starty anyhow.
Also, you're misusing sizeof(). You probably want sizeof(rgb) instead.
Why not use a structure? If the code has no intention of being portable you could easily get away with:
struct rgb_bits {
int red : 8;
int green : 8;
int blue : 8;
};
union rgb {
rgb_bits colour;
long array;
}
Blanking out the pixel then simply becomes:
union rgb pixel;
pixel.array = 0;
and setting individual colours becomes:
union rgb pixel;
pixel.colour.red = ...;
pixel.colour.green = ...;
pixel.colour.blue = ...;
Looks like you're storing your single pixel value in the pointer to your data to me:
rgb = rgbpixel;