PGM File Processing in C - c

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.

Related

Load string containing words from file

I need to load strings from file into a struct array.
CORRECT OUTPUT:
4
Sarajevo,345123
Tuzla,123456
Mostar,101010
Banja Luka,234987
MY OUTPUT:
1
Sarajevo 345123
Tuzla 123456
Mostar 101010
Banja Luka 234987,544366964
Code:
#include <stdio.h>
#include <string.h>
struct City {
char name[31];
int number_of_citizen;
};
int load(struct City cities[100], int n) {
FILE *fp = fopen("cities.txt", "r");
int i = 0;
while (fscanf(fp, "%[^,]s %d\n", cities[i].name, &cities[i].number_of_citizen)) {
i++;
if (i == n)break;
if (feof(fp))break;
}
fclose(fp);
return i;
}
int main() {
int i, number_of_cities;
struct City cities[10];
FILE* fp = fopen("cities.txt", "w");
fputs("Sarajevo 345123", fp); fputc(10, fp);
fputs("Tuzla 123456", fp); fputc(10, fp);
fputs("Mostar 101010", fp); fputc(10, fp);
fputs("Banja Luka 234987", fp);
fclose(fp);
number_of_cities = load(cities, 10);
printf("%d\n", number_of_cities);
for (i = 0; i < number_of_cities; i++)
printf("%s,%d\n", cities[i].name, cities[i].number_of_citizen);
return 0;
}
Could you explain me how to fix this? Why my program only loaded 1 city?
The fscanf() conversion string is incorrect: instead of "%[^,]s %d\n" you should use:
while (i < n && fscanf(fp, "%30[^,],%d",
cities[i].name,
&cities[i].number_of_citizen) == 2) {
i++;
}
Or better:
#include <errno.h>
#include <stdio.h>
#include <string.h>
int load(struct City cities[], int n) {
char buf[200];
int i = 0;
char ch[2];
FILE *fp = fopen("cities.txt", "r");
if (fp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", "cities.txt",
strerror(errno));
return -1;
}
while (i < n && fgets(buf, sizeof buf, fp)) {
if (sscanf(buf, "%30[^,],%d%1[\n]",
cities[i].name,
&cities[i].number_of_citizen, ch) == 3) {
i++;
} else {
fprintf(stderr, "invalid record: %s\n", buf);
}
}
fclose(fp);
return i;
}
Also change your main function to output commas between the city names and population counts:
int main() {
int i, number_of_cities;
struct City cities[10];
FILE *fp = fopen("cities.txt", "w");
if (fp) {
fputs("Sarajevo,345123\n", fp);
fputs("Tuzla,123456\n", fp);
fputs("Mostar,101010\n", fp);
fputs("Banja Luka,234987\n", fp);
fclose(fp);
}
number_of_cities = load(cities, 10);
printf("%d\n", number_of_cities);
for (i = 0; i < number_of_cities; i++)
printf("%s,%d\n", cities[i].name, cities[i].number_of_citizen);
return 0;
}
EDIT: since there are no commas in the database file, you must use a different parsing approach:
#include <errno.h>
#include <stdio.h>
#include <string.h>
int load(struct City cities[], int n) {
char buf[200];
int i = 0;
FILE *fp = fopen("cities.txt", "r");
if (fp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", "cities.txt",
strerror(errno));
return -1;
}
while (i < n && fgets(buf, sizeof buf, fp)) {
/* locate the last space */
char *p = strrchr(buf, ' ');
if (p != NULL) {
/* convert it to a comma */
*p = ',';
/* convert the modified line */
if (sscanf(buf, "%30[^,],%d",
cities[i].name,
&cities[i].number_of_citizen) == 2) {
i++;
continue;
}
}
fprintf(stderr, "invalid record: %s", buf);
}
fclose(fp);
return i;
}

Storing all the values of a PPM P3 file

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;
}

C pass by reference "returns" incorrect content

I want to read some values from a file using a function and pass them to main.
The file has specific format:
string double char
For example 2 lines:
blahblah 0.12 G
testtesttest 0.33 E
I have the following program. Although values are printed correctly in the function, in main only a few of them are printed. The rest are 0.00000 and no character is printed as well. What am I doing wrong?
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int read_file(const char *filename, double **prob, char **sense);
int main(){
double *iprob;
char *sense;
read_file("test.txt", &iprob, &sense);
printf("Main: %lf %c\n", iprob[0], sense[0]);
return 0;
}
int read_file(const char *filename, double **prob, char **sense){
FILE *fp;
char line[100], temp[80];
int i = 0;
fp = fopen(filename, "r");
if (fp == NULL){
fprintf(stderr,"File %s not found!\n", filename);
return 0;
}
//*prob = (double *)malloc(sizeof(double) * 100);
//*sense = (char *)malloc(sizeof(char) * 100);
while( fgets(line, 100, fp) != NULL){
prob[i] = (double *)malloc(sizeof(double));
sense[i] = (char *)malloc(sizeof(char));
if ( sscanf(line, "%s %lf %c", temp, prob[i], sense[i]) < 3 ){
fprintf(stderr, "Parsing error detected at line %d!", i);
fclose(fp);
return 0;
}
else{
printf("%lf %c\n", *prob[i], *sense[i]);
}
i++;
}
fclose(fp);
return 1;
}
You use a double pointer to double in your functions, because you want to update the pointer passed in from main.
The problem is, that the allocated array is in *prob, and therefore you have to address the elements of that array as (*prob)[i].
*prob[i] is the same as *(prob[i]). prob is the pointer to a pointer; it has only one element, so to speak, so any index except 0 is invalid here.
Below is a correction of your code:
It reads in as many entries as there are in the file by reallocating memory as needed.
It returns -1 on failure and the number of items when successful, so you know how many items you can safely address.
You should free both pointers after use.
So:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int read_file(const char *filename, double **prob, char **sense);
int main(){
double *iprob = NULL;
char *sense = NULL;
int i, n;
n = read_file("test.txt", &iprob, &sense);
for (i = 0; i < n; i++) {
printf("Main: %lf %c\n", iprob[i], sense[i]);
}
free(iprob);
free(sense);
return 0;
}
int read_file(const char *filename, double **prob, char **sense){
FILE *fp;
char line[100];
int size = 0;
int i = 0;
*prob = NULL;
*sense = NULL;
fp = fopen(filename, "r");
if (fp == NULL) return -1;
while (fgets(line, sizeof(line), fp) != NULL) {
char temp[80];
if (i >= size) {
size += 8;
*prob = realloc(*prob, size * sizeof(**prob));
*sense = realloc(*sense, size * sizeof(**sense));
if (*prob == NULL || *sense == NULL) {
fclose(fp);
return -1;
}
}
if (sscanf(line, "%79s %lf %c", temp, &(*prob)[i], &(*sense)[i]) < 3) {
fprintf(stderr, "Parsing error detected at line %d!", i);
fclose(fp);
return -1;
}
printf("%lf %c\n", (*prob)[i], (*sense)[i]);
i++;
}
fclose(fp);
return i;
}
change to
*prob = (double *)malloc(sizeof(double) * 100);
*sense = (char *)malloc(sizeof(char) * 100);
while( fgets(line, 100, fp) != NULL){
//prob[i] = (double *)malloc(sizeof(double));
//sense[i] = (char *)malloc(sizeof(char));
if ( sscanf(line, "%s %lf %c", temp, &(*prob)[i], &(*sense)[i]) < 3 ){
fprintf(stderr, "Parsing error detected at line %d!", i);
fclose(fp);
return 0;
}
else{
printf("%lf %c\n", (*prob)[i], (*sense)[i]);
}
i++;
}

C - Opening differents files using same pointer

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;
}

Using fread to store data into a char buffer

I am working on a project where I need to read data from a binary file. I am trying to store the data into a char buffer. Suppose the binary file consisted of a character, an int and a double what size would the char buffer need to be ? And how would I convert back into int's and doubles ?
I am reading the data into a char buffer because it would improve the speed of my program.
Thanks!
The following example program fread()s the first DATASIZE sets of a char, an int and a float from a file specified on the command line:
typedef struct Data_s {
char c;
int i;
float f;
} Data_t;
#define DATASIZE 3
int main(int argc, char ** argv) {
if (1 >= argc) {
fprintf(stderr, "usage: %s <file name>\n", argv[0]);
return EXIT_SUCCESS;
}
{
FILE * f = fopen(argv[1], "r");
if (!f) {
perror("fopen() failed.");
return EXIT_FAILURE;
}
{
Data_t data[DATASIZE];
size_t sizeData = sizeof(*data);
size_t sizeToRead = sizeof(data)/sizeData;
memset(data, 0, sizeToRead * sizeData);
size_t sizeRead = fread(&data, sizeData, sizeToRead, f);
if (0 != fclose(f))
perror("fclose() failed,");
if (sizeToRead != sizeRead) {
perror("fread() failed.");
return EXIT_FAILURE;
}
for (size_t i = 0; i < sizeToRead; ++ i)
printf("read c=0x%02hhx, i=%d, f=%f from '%s'\n", data[i].c, data[i].i, data[i].f, argv[1]);
}
}
return EXIT_SUCCESS;
}
You can use the fscanf function to read the data from the file straight into eagerly awaiting variables:
char c;
int i;
double d;
FILE *fp = fopen("C:\\example.txt", "rb");
if (fp)
{
fscanf(fp, "%c%d%lf", &c, &i, &d);
fclose(fp);
printf("Character: %c\nInteger: %d\nDouble: %lf\n", c, i, d);
}
EDIT: If you're looking for more info on fscanf, see here
EDIT2: Binary Solution
FILE *fp = fopen("C:\\example.txt", "rb");
if (fp)
{
char buffer[sizeof(int) + sizeof(double) + sizeof(char)];
if (fread(buffer, 1, sizeof(buffer), fp) == sizeof(buffer))
{
char c = *(char*)buffer;
int i = *(int*)(buffer + sizeof(char));
double d = *(double*)(buffer + sizeof(char) + sizeof(int));
}
fclose(fp);
}

Resources