RockAndaHardPlace RockAndaHardPlace - 1 month ago 10
C Question

c - Segmentation fault when trying to write a modified structure

This is in a program meant to work with ppm image files.

I'm getting a compilation error when trying to modify a struct and then writing it to a new file.

This is the global struct (declared in ppmIO.c and ppmIO.h):

ppmIO.c:

struct Image *instance;


ppmIO.h:

struct Image
{
int width;
int height;
unsigned char *data;
};

extern struct Image *instance;


This is my imageManip.h file:

#include <ppmIO.h>

void ImageInvert(struct Image **toInvert);

void ImageSwap(struct Image **toSwap);


These are the relevant parts of my imageManip.c file:

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <ppmIO.h>
#include <imageManip.h>

void ImageInvert(struct Image **toInvert) {


int i;
int pix = (*toInvert->width) * (*toInvert->height);

*toInvert = realloc(*toInvert, 2* sizeof *instance);

for (i = 0; i < pix; i++)
{
*(toInvert)->data = ((unsigned char)255 - *(toInvert)->data));
*(toInvert)->data = ((unsigned char)255 - *(toInvert)->data++));
*(toInvert)->data = ((unsigned char)255 - *(toInvert)->data++));
}

}

void ImageSwap(struct Image **toSwap) {

int i;
int pix = (*toSwap)->width * (*toSwap)->height;

*toSwap = realloc(*toSwap, 2* sizeof *instance);

unsigned char what = (*toSwap)->data;

for (i = 0; i < pix-1; i++)
{
(*toSwap)->data = (*toSwap)->data++;
(*toSwap)->data = (*toSwap)->data++;
(*toSwap)->data = what;
what = (*toSwap)->data++;
}

}


This is the ImageWrite method, used to write the modified image structure to a file:

void ImageWrite(char *filename)
{
int num;
printf("%d", num);
int size = (instance->width) * (instance->height) * 3;


FILE *fp = fopen(filename, "w");

if (!fp) die("cannot open file for writing\n");

fprintf(fp, "P6\n%d %d\n%d\n", instance->width, instance->height, 255);

num = fwrite((void *) instance->data, 1, (size_t) size, fp);

if (num != size) die("cannot write image data to file\n");

fclose(fp);
}


This is how I call my modifying functions from main:

ImageInvert(&instance);
ImageSwap(&instance);
ImageWrite(first); //where first is a filename


This is the segmentation fault that gdb reports:

Program received signal SIGSEGV, Segmentation fault.
__mempcpy_sse2 () at ../sysdeps/x86_64/memcpy.S:166
166 ../sysdeps/x86_64/memcpy.S: No such file or directory.


Someone suggested that in my modifying funtions (ImageInvert and ImageSwap), I keep changing the pointer, not the data pointed at. If that is the case, how can I change the data pointed at instead of just the pointer?

Answer

As noted in comments to a previous question, the code for ImageInvert() can be made much simpler.

Using subscript notation:

void ImageInvert(struct Image **toInvert)
{
    struct Image *image = *toInvert;
    int n_colour_vals = (image->width * image->height) * 3;
    unsigned char *data = image->data;

    for (int i = 0; i < n_colour_vals; i++)
        data[i] = 255 - data[i];
}

Using pointers:

void ImageInvert(struct Image **toInvert)
{
    struct Image *image = *toInvert;
    unsigned char *data = image->data;
    unsigned char *end = data + (image->width * image->height) * 3;

    while (data < end)
    {
        *data = 255 - *data;
        data++;
    }
}

Equivalent changes can probably be made to imageSwap(), though I am not entirely sure what it is supposed to be doing. There were problems in the previous question that might have suggested that the reallocation was a good idea, but (at least for ImageInvert()), that really isn't needed.