I am "attempting" to store P3 PPM files using C but I'm not all that experienced with it so I've hit a brick wall. I was wondering if anyone could help me in accomplishing my task. Thank you.
I would like to keep them as struct PPM and struct PPM * getPPM(File * fd) but the contents can be altered.
I also don't know how to store the comments and would like to do that too.
Basically I am trying to store the data as follows:
P3
#comment.1
. . .
#comment.n
width height
max
r1 g1 b1
r2 g2 b2
r3 g3 b3
. . .
Edit:
I have done the changes for it to compile correctly and now I am trying to pass argv so that the file may read argv[1] to get the file name. When I do so i receive a Segmentation error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Holds the data
struct data {int r,g,b;};
struct PPM {char code[4]; char comments; int width; int height; int max; struct data *Data;};
//Gets the PPM data
struct PPM* GetPPM(FILE * fd, argv)
{
char readChars[256] = {0};
//Allocates memory for PPM
struct PPM *image = (struct PPM *)calloc(1, sizeof(struct PPM));
int i;
fgets(image->code, sizeof(image->code), fd);
fd = fopen(argv[1], "r");
//Checks if file is type P3
if((image->code[0] != 'P') && (image->code[0] != '3'))
{
return NULL;
}
image->code[2] = '\0';
//Checks for comments then continues around the loop until there's no more
fgets(readChars, sizeof(readChars), fd);
while(readChars[0] == '#')
{
fgets(readChars, sizeof(readChars), fd);
}
//Checks for PPM width, height and max
sscanf(readChars, "%d %d", &image->width, &image->height);
fgets(readChars, sizeof(readChars), fd);
sscanf(readChars, "%d", &image->max);
image->Data = (struct data*)malloc(image->width * image->height * sizeof(struct data));
i = 0;
while(fgets(readChars, sizeof(readChars), fd));
{
sscanf(readChars, "%d %d %d", &(image->Data[i].r), &(image->Data[i].g), &(image->Data[i].b));
++i;
}
fclose(fd);
return image;
}
//Deallocates memory
void freePPM(struct PPM *image)
{
free(image->Data);
free(image);
}
//Displays PPM
void showPPM(struct PPM *image)
{
int i = 0;
int totalpixels = image->width * image->height;
printf("%s\n", image->code);
printf("%d %d\n", image->width, image->height);
printf("%d\n", image->max);
for(i = 0; i < totalpixels; ++i)
{
printf("%d %d %d\n", image->Data[i].r, image->Data[i].g, image->Data[i].b);
}
}
int main(int argc, char ** argv)
{
struct PPM *image = GetPPM(argv);
showPPM(image);
freePPM(image);
return 0;
}
There are some error in declaring structures and the way data is read. Check how the data is read in the following code and come back here if you want more clarity.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data {int r,g,b;};
struct PPM {char code[4]; char comments; int width; int height; int max; struct data *Data;};
struct PPM* GetPPM(FILE * fd)
{
char readChars[256] = {0};
struct PPM *image = (struct PPM *)calloc(1, sizeof(struct PPM));
int i;
fgets(image->code, sizeof(image->code), stdin);
if((image->code[0] != 'P') && (image->code[0] != '3'))
{
return NULL;
}
image->code[2] = '\0';
fgets(readChars, sizeof(readChars), stdin);
while(readChars[0] == '#')
{
fgets(readChars, sizeof(readChars), stdin);
}
sscanf(readChars, "%d %d", &image->width, &image->height);
fgets(readChars, sizeof(readChars), stdin);
sscanf(readChars, "%d", &image->max);
image->Data = (struct data*)malloc(image->width * image->height * sizeof(struct data));
i = 0;
while(fgets(readChars, sizeof(readChars), stdin))
{
sscanf(readChars, "%d %d %d", &(image->Data[i].r), &(image->Data[i].g), &(image->Data[i].b));
++i;
}
return image;
}
void FreePPM(struct PPM *image)
{
free(image->Data);
free(image);
}
void PrintPPM(struct PPM *image)
{
int i = 0;
int totalpixels = image->width * image->height;
printf("%s\n", image->code);
printf("%d %d\n", image->width, image->height);
printf("%d\n", image->max);
for(i = 0; i < totalpixels; ++i)
{
printf("%d %d %d\n", image->Data[i].r, image->Data[i].g, image->Data[i].b);
}
}
int main()
{
struct PPM *image = GetPPM(stdin);
PrintPPM(image);
FreePPM(image);
return 0;
}
Related
I am using C in Visual Studio via a remote Linux server. I want to read a file and store the contents in a array of structs. Every time I try to read a line using fscanf() it seg faults. Thanks in advance.
Format of the file I'm trying to read:
F150 5.4 28000 white
RAM1500 5.7 32000 orange
car 4.5 12000 green
truck 6.1 55000 black
Here's a simplified version my program as the other parts function fine:
#include <stdlib.h>
#include <stdio.h>
struct data {
char name[20];
float floatNum;
int intNum;
char color[20];
} temp;
int scan(void) {
int size = 0;
FILE *data;
data = fopen("./hw3.data", "r");
while (1) {
fscanf(data, "%s %f %d %s", temp.name, &temp.floatNum,
&temp.intNum, temp.color);
if (feof(data))
break;
size++;
}
return size;
}
void load(int size, struct data autos[]) {
int i;
FILE *data;
data = fopen("./hw3.data", "r");
for (i = 0; i < size; i++) {
fscanf(data, "%s %f %d %s", autos[i].name, &autos[i].floatNum,
&autos[i].intNum, autos[i].color);
}
}
int main() {
int size;
struct data *autos;
size = scan();
autos = malloc(size * sizeof(struct data));
load(size, autos);
return 0;
}
There are multiple possible causes for problems:
you do not test if fopen() succeeds: if the file cannot be opened, the FILE pointer data will be null, causing undefined behavior in fscanf(), possibly a seg fault.
you do not test if malloc succeeds... again causing a seg fault if memory cannot be allocated.
you should close the FILE after reading
your test for feof() is incorrect: it might be true after successfully reading the last item, causing it to be ignored and you might never reach the end of file if one of the items cannot be read. You should just test the return value of fscanf(): it returns the number of successful conversions, so 4 in your case.
you should use %19s to avoid writing beyond the end of the targets arrays, another potential source of undefined behavior.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data {
char name[20];
float floatNum;
int intNum;
char color[20];
};
int scan(const char *filename) {
struct data temp;
int size = 0;
FILE *data = fopen(filename, "r");
if (data == NULL) {
fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
return -1;
}
while (fscanf(data, "%19s %f %d %19s",
temp.name, &temp.floatNum,
&temp.intNum, temp.color) == 4) {
size++;
}
fclose(data);
return size;
}
int load(const char *filename, int size, struct data autos[]) {
int i;
FILE *data = fopen(filename, "r");
if (data == NULL) {
fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
return -1;
}
for (i = 0; i < size; i++) {
if (fscanf(data, "%19s %f %d %19s",
autos[i].name, &autos[i].floatNum,
&autos[i].intNum, autos[i].color) != 4)
break;
}
fclose(data);
return i;
}
int main() {
char filename[] = "./hw3.data";
int size = scan(filename);
if (size < 0)
return 1;
if (size > 0) {
struct data *autos = malloc(size * sizeof(struct data));
if (autos == NULL) {
fprintf(stderr, "cannot allocate %zu bytes\n", size * sizeof(struct data));
return 1;
}
int n = load(filename, size, autos);
for (int i = 0; i < n; i++) {
printf("%s %g %d %s\n", autos[i].name, autos[i].floatNum,
autos[i].intNum, autos[i].color);
}
free(autos);
}
return 0;
}
New to C, I'm trying to read an input PGM file that's either P2, P5, or P6 along with an output file from the command prompt, then read the data to a buffer, and finally write it to the output file. Everything is compiling but when I view the output file only P2 looks like the original file. P5 and P6 look like a rainbow mess. I'm including my code.
#include <stdio.h>
#include <stdlib.h>
unsigned char* getPGMfile(char filename[], int *lwidth, int *lheight, int *lchannel);
int save(char filename[], unsigned char*data, int lwidth, int lheight, int lchannel);
int main(int argc, char **argv){
int lwidth, lheight, lchannel;
getPGMfile(argv[1], &lwidth, &lheight, &lchannel);
unsigned char* data=(getPGMfile(argv[1], &lwidth, &lheight, &lchannel));
printf("width, height, channel: %d %d %d\n",lwidth,lheight,lchannel);
save(argv[2], data, lwidth, lheight, lchannel);
return 0;
}
unsigned char* getPGMfile (char filename[], int *lwidth, int *lheight, int *lchannel){
FILE *in_file;
char ch;
int row, col, type;
int ch_int;
in_file = fopen(filename, "r");
if (in_file == NULL){
fprintf(stderr, "Unable to open file %s\n\n", filename);
exit(8);
}
printf("\nReading image file: %s\n", filename);
ch = getc(in_file);
if(ch != 'P'){
printf("Not valid pgm/ppm file type\n");
exit(1);
}
ch = getc(in_file);
type = ch - 48;
if((type != 2) && (type != 5) && (type != 6)){
printf("Not valid pgm/ppm file type\n");
exit(1);
}
while(getc(in_file) != '\n');
while (getc(in_file) == '#'){
while (getc(in_file) != '\n');
}
fseek(in_file, -1, SEEK_CUR);
int width, height;
fscanf(in_file,"%d%d", &width, &height);
printf("width and heigth: %d %d\n", width, height);
int intensity;
fscanf(in_file,"%d", &intensity);
printf("intensity: %d\n", intensity);
unsigned char *data;
if(type == 2){
*lchannel=5;
int k=0;
data = (unsigned char *) malloc((width*height)*sizeof(unsigned char));
for (row=height-1; row >=0; row--)
for (col=0; col<width; col++){
fscanf(in_file,"%d", &ch_int);
data[k]=ch_int;k++;
}
}
else if(type == 5){
*lchannel=6;
data=(unsigned char *) malloc(width*height*sizeof(unsigned char));
fread(data, 1, (width*height), in_file);
}
else if(type == 6){
*lchannel=6;
data=(unsigned char *) malloc(3*(width*height)*sizeof(unsigned char));
fread(data, 1, (3*(width*height)), in_file);
}
fclose(in_file);
printf("\nDone reading file\n");
*lwidth=width;
*lheight=height;
return data;
}
int save(char filename[],unsigned char *data, int lwidth, int lheight, int lchannel){
FILE *fp;
fp = fopen(filename, "wb");
const int dimx = 800, dimy = 800;
int i,j;
if(lchannel == 5){
fprintf(fp,"P5\n%u %u\n255\n", lwidth, lheight);
fwrite(data,1,(lwidth*lheight),fp);
printf("File %s saved.\n",filename);
}
else if(lchannel == 6){
fprintf(fp,"P6\n%u %u\n255\n", lwidth, lheight);
for(j=0;j<dimy;++j){
for(i=0;i<dimx;++i){
static unsigned char color[3];
color[0]=i%256;
color[1]=j%256;
color[2]=(i*j)%256;
fwrite(color,1,3,fp);
}
}
printf("File %s saved.\n",filename);
}
fclose(fp);
return(0);
free(data);
}
The fread size should be sizeof(unsigned char) rather than 1.
I am at a lost here, I don't understand why s = (struct Person *)malloc(sizeof(struct Person) * n); won't work? This assignment is to find the BMI in the data.txt file. Which only contain this
3
Pikachu 50 37
Godzilla 1000 1000
Holmes 178 67
and output it onto a BMI.txt file. With the requirement for Allocate memory block. Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define STUDENT 3
struct Person {
float mass, height;
float bmi;
int count, num;
char name[99];
};
typedef struct Person Person;
int main()
{
int i;
FILE *in, *out;
in = fopen("data.txt", "r");
if (in == NULL) {
printf("failed to open file!\n");
exit(1);
}
out = fopen("bmi.txt", "w");
struct Person s[STUDENT];
s = (struct Person *)malloc(sizeof(struct Person) * i);
for (i = 0; i < 3; i++) {
fscanf("%s", &s[i].name);
fscanf("%lf", &s[i].height);
fscanf("%lf", &s[i].weight);
bmi = mass / (pow(height, 2));
fprintf(out, "%s%3.2f\n", name, bmi);
}
free(s);
}
fclose(in);
fclose(out);
}
This
s = (struct Person *)malloc(sizeof(struct Person) * n);
is not only wrong, but unnecessary, s is already an array of struct Person so you cannot assign to it, and you don't need to malloc() space for it.
Maybe you need this
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define STUDENT 3
struct Person {
int mass, height;
int bmi;
int count, num;
char name[99];
};
typedef struct Person Person;
int main()
{
int i;
int n;
struct Person *s;
FILE *in;
FILE *out;
in = fopen("data.txt", "r");
if (in == NULL) {
printf("failed to open file!\n");
exit(1);
}
out = fopen("bmi.txt", "w");
if (out == NULL) {
printf("failed to open file!\n");
fclose(in);
exit(1);
}
n = 3;
s = malloc(sizeof(struct Person) * n);
if (s == NULL) {
printf("failed to open file!\n");
fclose(in);
fclose(out);
exit(1);
}
for (i = 0; i < n; i++) {
fscanf("%s", s[i].name);
fscanf("%d", &s[i].height);
fscanf("%d", &s[i].mass);
bmi = mass / (pow(height, 2));
fprintf(out, "%s%d\n", name, bmi);
}
free(s);
fclose(in);
fclose(out);
}
and there is no need to cast from void * to any other pointer type, so don't cast malloc().
I'm trying to retrieve informations by many plain-text files, which will be then stored in a proper struct. To do so, I'm using a function that takes member of the struct to populate and source of the plain-text file where the informations are stored.
Posting my "test" code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct _elem
{
const char *title;
int ok;
int almost;
int nope;
int hits;
float last_rank;
};
typedef struct _elem Chapter;
Chapter *generate_array(const char *source, int *elems);
int engine_start(Chapter *elem, char *source);
int main()
{
const char path_f[100];
int elements = 0;
int i = 0;
Chapter *dict;
printf("Insert the name of the source:\n");
scanf("%s", path_f);
printf("\nGenerating dictionary, please wait...\n");
dict = generate_array(path_f, &elements);
if (dict == NULL)
{
printf("Aborting.\n");
exit(1);
}
while (i < elements)
{
printf("Element %d:\n", (i + 1));
printf("\nTitle: %s\n", dict[i].title);
printf("Ok: %10d\n", dict[i].ok);
printf("Almost: %5d\n", dict[i].almost);
printf("Nope: %8d\n", dict[i].nope);
printf("Hits: %8d\n", dict[i].hits);
printf("Rank: %8.2f\n", dict[i].last_rank);
printf("\n");
i++;
}
return EXIT_SUCCESS;
}
Chapter *generate_array(const char *source, int *elems)
{
FILE *src;
int sources;
int i = 0;
char **srcs;
Chapter *generated;
src = fopen(source, "r");
if (src == NULL)
{
printf("[!!] Error while reading file!\n");
return NULL;
}
fscanf(src, "%d", &sources);
if (sources <= 0)
{
printf("[!!] Wrong number of sources, exiting.\n");
return NULL;
}
srcs = (char **) malloc(sizeof(char *) * sources);
while (i < sources && !feof(src))
{
srcs[i] = (char *) malloc(sizeof(char) * 100);
fscanf(src, "%s", srcs[i++]);
}
fclose(src);
generated = (Chapter *) malloc(sizeof(Chapter) * i);
*elems = i;
i = 0;
while (i < *elems)
{
if(engine_start( &generated[i], srcs[i] )) i++;
else
{
printf("[!!] Error in file %s, aborting.\n", srcs[i]);
return NULL;
}
}
return generated;
}
int engine_start(Chapter *elem, char *source)
{
FILE *parser;
int done = 0;
parser = fopen(source, "r");
if (parser == NULL) printf("[!!] Error while opening %s, aborting.\n", source);
else
{
fgets(elem->title, 100, parser);
fscanf(parser, "%d %d %d %d %f", &(elem->ok), &(elem->almost),
&(elem->nope), &(elem->hits),
&(elem->last_rank) );
fclose(parser);
done = 1;
}
return done;
}
Now this is the main file where are stored paths to the other plain-text files:
lol.dat
5
lold/lol1.dat
lold/lol2.dat
lold/lol3.dat
lold/lol4.dat
lold/lol5.dat
And one example of lolX.dat:
Qual'รจ la vittoria di cristo?
3 4 5 12 44.9
I'm getting SIGSEGV after the first iteration of "engine_start", probably due to FILE *parser (but I can be totally wrong, I don't know at this point).
Someone can guide me through this problem? Thank you.
Make the following changes and try-
struct _elem
{
char *title; // allocate the memory for this.
int ok;
int almost;
int nope;
int hits;
float last_rank;
};
You need to allocate memory for element title before assigning something to it.
int engine_start(Chapter *elem, char *source)
{
FILE *parser;
int done = 0;
parser = fopen(source, "r");
if (parser == NULL) printf("[!!] Error while opening %s, aborting.\n", source);
else
{
elem->title=(char *)malloc(100); // include this line.
fgets(elem->title, 100, parser);
fscanf(parser, "%d %d %d %d %f", &(elem->ok), &(elem->almost),
&(elem->nope), &(elem->hits),
&(elem->last_rank) );
fclose(parser);
done = 1;
}
return done;
}
So I am trying to read in a file and store it into my data struct, but every time I run it it either reads in garbage data and my struct is filled with 0s. Any suggestions?
I have functions to check if the data is valid, because my struct cannot store data that it has already stored (e.g same port or vmn).
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
typedef struct DataType{
double timeOffset;
int vmn;
int port;
}Data;
void insertDataType(Data *Data, double timeOffset, int vmn, int port){
Data->timeOffset = timeOffset;
Data->vmn = vmn;
Data->port = port;
}
double returnTimeOffset(Data D){
assert(D.timeOffset != 0.0);
return D.timeOffset;
}
int returnVMN(Data D){
assert(D.vmn != 0);
return D.vmn;
}
int returnPort(Data D){
assert(D.port != 0);
return D.port;
}
bool vmnValid(Data *Data, int n, int vmn){
int i;
for(i = 0; i <= n; i++){
if(Data[i].vmn != 0){
if(Data[i].vmn == vmn){
printf("Invalid vmn %d: vmn already inserted \n", vmn);
return false;
}
}
}
return true;
}
bool timeValid(Data *Data, int n, double timeOffset){
int i;
for(i = 0; i <= n; i++){
if(Data[i].timeOffset != 0.0){
if(Data[i].timeOffset == timeOffset){
printf("Invalid timeOffset %2lf: timeOffset already used \n", timeOffset);
return false;
}
}
}
return true;
}
bool portValid(Data *Data, int n, int port){
int i;
for(i = 0; i <= n; i++){
if(Data[i].port != 0){
if(Data[i].port == port){
printf("Invalid port %d: port already in use\n", port);
return false;
}
}
}
return true;
}
int main(int argc, const char * argv[]){
int n = 0;
int i = 0;
char c;
FILE *file;
// Open file
file = fopen("connect1.in", "r");
if (file == NULL) {
fprintf(stderr, "Invalid input file \n");
exit(1);
}
// Get number of lines (n)
while((c = fgetc(file))!= EOF){
if(c == '\n'){
n++;
}
}
printf("n = %d \n", n);
// Create a strut DataType of size n
Data *storage;
storage = calloc(n, sizeof(struct DataType));
// Read and insert the data
double timeOffset;
int vmn;
int port;
printf("\n");
while(fscanf(file, "%lf,%d,%d,", &timeOffset, &vmn, &port != EOF)){
printf("%lf %d %d \n", timeOffset, vmn, port);
if(timeValid(storage, n, timeOffset)){
if(vmnValid(storage, n, vmn)){
if(portValid(storage, n, port)){
insertDataType(&storage[vmn], timeOffset, vmn, port);
}
}
}
}
printf("\n");
printf("\n");
printf("Storage:\n");
for(i = 0; i <= n; i++){
printf("%3d: %2lf %d %d \n", i, storage[i].timeOffset, storage[i].vmn, storage[i].port);
}
}
After counting the number of lines the file pointer must be reset to the start of the file again.
Use the rewind() call which resets the file position back to file start after the line counting loop:
rewind(file);
Change
// while(fscanf(file, "%lf,%d,%d,", &timeOffset, &vmn, &port != EOF)){
while(fscanf(file, "%lf,%d,%d,", &timeOffset, &vmn, &port) != EOF){
// or better
while (fscanf(file, "%lf,%d,%d,", &timeOffset, &vmn, &port) == 3) {
#suspectus is correct, add rewind(file);
// change
// char c;
int c;
Minor considerations:
Data *storage;
// storage = calloc(n, sizeof(struct DataType));
// I like the style
storage = calloc(n, sizeof(*storage));
// In a number of places, function do not change *Data, so use `const`
// Useful to now, at a glance, that *Data is unchanged
// and forces the compiler to warn otherwise.
// bool vmnValid(Data *Data, int n, int vmn){
bool vmnValid(const Data *Data, int n, int vmn) {