I wrote a program in C to open bitmap image and save the dimension the image. i am having some problem to write the fread() function. please tell me what should be the correct format for the function in the code that i have written.
here i have used pointer array because i have to open multiple bitmap images.
#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
void fskip(FILE *fp, int num_bytes)
{
int i;
for (i=0; i<num_bytes; i++)
fgetc(fp);
}
typedef struct tagBITMAP /* The structure for a bitmap. */
{
int width;
int height;
//unsigned char *data;
} BITMAP;
int main()
{
int temp1=0;
BITMAP *bmp[50];
FILE *fp = fopen("splash.bmp","rb");
if (fp!=NULL && (fgetc(fp)=='B' && fgetc(fp)=='M')){
bmp[temp1] = (BITMAP *) malloc (sizeof(BITMAP));
fskip(fp,16);
fread(&bmp[temp1].width, sizeof(int), 1, fp);
fskip(fp,2);
fread(&bmp[temp1].height,sizeof(int), 1, fp);
fclose(fp);
}
else exit(0);
getch();
}
fread(&bmp[temp1].width, sizeof(int), 1, fp);
should be:
fread(&(bmp[temp1]->width), sizeof(int), 1, fp);
because bmp[temp1] is address of struct use -> operator instead of . Same error is in second fread().
. DOT that works with value variable called element selection by reference.
-> is used called element selection through pointer.
Related
As part of a college assignment, I'm trying to do a simple C app, using Win32 for GUI programming and writing my own dynamic linked list for storing data. Since i could use it for other things later, I'm trying to write a generic list, with "built in" functions for reading and writing data to a file. Now here's my problem
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tagA{
int t_int;
float t_float;
char t_char;
char t_vchar[30];
} A;
typedef struct tagB{
void *data;
struct tagB *prox;
} B;
int main(){
A dA = {1, 1.5, 'a', "teste123"};
B dB = {&dA, NULL};
dB.data = &dA;
B dB2 = {0};
FILE *fp;
fp = fopen("Data.txt", "w");
size_t dSize = sizeof(dA);
printf("Struct size: %d", dSize);
if(fp == NULL){
printf("nope");
}else{
fwrite(&dB.data, dSize, 1, fp);
}
fclose(fp);
fp = fopen("Data.txt", "r");
dB2.data = malloc(dSize);
fread(&dB2.data, dSize, 1, fp);
printf("\n\n%s", ((A*)dB2.data)->t_vchar);
}
This is the code I'm trying to work out.
The writing works just fine, and I just have to make it to a separate function that receives the pointer to the data struct and its size.
But the reading is off... Once read and printed to the console, the t_int shows a really large number, the t_float has nothing, and so the char and string...
Also, I know its not the best written, most efficient and safe code, but it's just a prototype, something that came into my mind...
Your problem is you are writing the address of &dB.data with fwrite instead of dB.data itself (it is already a pointer). For example:
fwrite(dB.data, dSize, 1, fp);
will resolve your problem (with the like corresponding change to fread).
void *data;
It's not useful to declare data as void*. Declare it as A *data; instead.
fwrite(&dB.data, dSize, 1, fp);
...
fread(&dB2.data, dSize, 1, fp);
dB2.data is a pointer, just use dB2.data. See example below. For better readability you can declare ptr_data instead of data
typedef struct tagA {
int t_int;
float t_float;
char t_char;
char t_vchar[30];
} A;
typedef struct tagB {
A *data;
struct tagB *prox;
} B;
int main() {
A dA = { 1, 1.5, 'a', "teste123" };
B dB = { 0 };
dB.data = &dA;
B dB2 = { 0 };
FILE *fp;
fp = fopen("Data.txt", "w");
size_t dSize = sizeof(dA);
printf("Struct size: %d", dSize);
if(fp == NULL) {
printf("nope");
}
else {
fwrite(dB.data, dSize, 1, fp);
}
fclose(fp);
fp = fopen("Data.txt", "r");
dB2.data = malloc(dSize);
fread(dB2.data, dSize, 1, fp);
printf("\n\n%s\n", dB2.data->t_vchar);
return 0;
}
Your error is at fwrite(), fread(). The first param of them is the pointer which points at the real data you want to write/read.
Since you want to read/write a struct A, the pointer must actually point at struct A, not struct A*.
Just replace
fwrite(&dB.data, dSize, 1, fp);
fread(&dB2.data, dSize, 1, fp);
with
fwrite(dB.data, dSize, 1, fp);
fread(dB2.data, dSize, 1, fp);
I have three structs :
struct Map
{
int width, height;
int* cases;
};
typedef struct Map Map;
struct Ship
{
int x, y, length, firstShoot, color, hasBeenDiscovered;
};
typedef struct Ship Ship;
struct Player
{
int activeShips;
Map map[2];
char lastMoves[5][128];
Ship ships[10];
int shipcolor[4];
int color;
};
typedef struct Player Player;
I use the map structure as a 2d dynamic array. Here are my functions to manipulate the map :
void mallocMap(Map* map, int width, int height)
{
map->cases = malloc(sizeof(int) * width * height);
map->width = width;
map->height = height;
if (map->cases == NULL)
{
printf("Erreur d'allocation de memoire\n");
exit(0);
}
}
void freeMap(Map* map)
{
free(map->cases);
}
int getMapValue(Map map, int x, int y)
{
return *(map.cases + y*map.width + x);
}
void setMapValue(Map* map, int value, int x, int y)
{
*(map->cases + y*map->width + x) = value;
}
Now what I'm doing is I'm creating a variable player of type Player, asks the user the width and height of the map and allocate memory for the map (malloc(sizeof(int)*width*height)).
Next what I want to do is to be able to store the struct Player in a file and the values of the cases but I don't know how I could do it.
Any suggestion ?
You're not reading the values back in properly:
fseek(file, sizeof(Player), SEEK_SET); // set the cursor after the struct
fread(&player->games, sizeof(int), 1, file); // read the value
fseek(file, sizeof(int), SEEK_CUR); // set the cursor after the first value
fread(&player->map.cases, sizeof(int), 1, file); // read the value
In the first read, you pass in &player->games as the address to write to. This expression has type int **. Rather than writing into the memory you allocated, you're writing into the pointer that contains that address. The same problem exists in the other read.
Remove the address-of operator from each of the fread calls. Also, the calls to fseek are redundant since the file pointer is already at the correct place, so you can remove them.
fread(player->games, sizeof(int), 1, file); // read the value
fread(player->map.cases, sizeof(int), 1, file); // read the value
First things first - my header (.h) file looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef struct riff_list {
char id[4];
uint32_t cksize;
char subid[4];
uint8_t *buf;
} list_t;
void write_u32_le(uint32_t n, FILE *f)
{
uint8_t i, buf[4];
for (i = 0; i < 4; i++)
{
buf[i] = n & 0xFF;
n >>= 8;
}
fwrite(buf, 1, 4, f);
}
void init_list_chunk(list_t list, char *cktype)
{
memcpy(list.id, "LIST", 4);
list.cksize = 0;
memcpy(list.subid, cktype, 4);
}
void write_list_chunk(list_t list, FILE *f)
{
fwrite(list.id, 1, 4, f);
write_u32_le(4 + list.cksize, f);
fwrite(list.subid, 1, 4, f);
fwrite(list.buf, 1, list.cksize, f);
}
Now, the problem is with a basic test program trying to write something to a file. This comes out as expected:
int main()
{
FILE *f;
list_t list;
memcpy(list.id, "LIST", 4);
list.cksize = 0;
memcpy(list.subid, "TEST", 4);
f = fopen("C:\\listtest.bin", "wb");
fwrite(list.id, 1, 4, f);
write_u32_le(4+list.cksize, f);
fwrite(list.subid, 1, 4, f);
list.buf = malloc(4);
fwrite(list.buf, 1, 4, f);
free(list.buf);
fclose(f);
}
While this just produces a 4096-byte file with junk, with no recognizable parts of what is expected (not even "LIST"):
int main()
{
FILE *f;
list_t list;
init_list_chunk(list, "TEST");
list.buf = malloc(4);
list.cksize += 4;
f = fopen("C:\\listtest.bin", "wb");
write_list_chunk(list, f);
free(list.buf);
fclose(f);
}
Why is this? Why does the latter approach not work as expected?
The expected output should be something like:
LIST
ssss
TEST
xxxx
Where "ssss" is the size and "xxxx" is any random data (4 bytes).
I have seen approaches that instead passes structs as pointers to them (&my_struct_var) and accesses the members in a function by deferencing them as my_struct_var->member, but can I pass the struct as it is?
Calling a function with out = func(in); means that if the function modifies the contents of in those modifications will only be visible within the function. When the function returns the calling function will still have the same contents in the variable in. Doing a call by value could be described as the called function gets its own copy of the variable.
You have two options to solve your problem:
1) As you already suggested yourself, your function init_list_chunk could take a pointer to your structure. By then modifying the structure the pointer points to those modifications will be usable also for the calling function.
2) Instead of returning void your init_list_chunk could return the modified structure. Something like: list = init_list_chunk(list, "TEST"); or even list = init_list_chunk("TEST"); as there is no useful input information within list at the time of the function call.
Im having some trouble with writing more than one struct to the file and then close the program. The next time I open the file and print whats in there, it displays strange text.
If I only choose to print 1 struct plus the obligatory first on that says how many structs are in the file (the first in the file) it displays correct.But as soon as there is more than two http://imgur.com/ANTCSAZ.
I have been looking for a couple hours for the solution but cant find it, would appreciate all the help I can get! :)
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
//#include "allafunktioner.h"
struct vinnare{
int ar;
char namn[20];
};
struct vinnare *inlasningTillFil(struct vinnare *vinnare, int antalvinnareinlasning);
int meny();
int vinnarear(int ar, char namnlista, int vinnare);
void artistnamn(int ar, char namnlista, int vinnare);
void skrivutalla(int ar, int namnlista, int vinnare);
main(){
int a=1, val, antalvinnareinlasning,test=0;
struct vinnare *vinnare;
FILE *file;
file = fopen("F:\\Uppgifter", "rb");
if (file == NULL){
vinnare = NULL;
printf("Ange antal vinnare:");
scanf("%d", &antalvinnareinlasning);
vinnare = (struct vinnare *)malloc(antalvinnareinlasning*sizeof(struct vinnare));
vinnare = inlasningTillFil(vinnare, antalvinnareinlasning);
}
else{
fread(&antalvinnareinlasning, sizeof(int), 1, file);
printf("%d", antalvinnareinlasning);
vinnare =(struct vinnare *)malloc(antalvinnareinlasning*sizeof(struct vinnare));
for (a = 1; a < (antalvinnareinlasning + 1); a++){
fread(&vinnare[a].ar, sizeof(int), 1, file);
fread(&vinnare[a].namn, sizeof(char)*20, 1, file);
printf("%d", vinnare[a].ar);
printf("%s", vinnare[a].namn);
}
}
fflush(stdin);
getchar();
}
struct vinnare *inlasningTillFil(struct vinnare *vinnare, int antalvinnareinlasning){
int a, temp;
FILE *file;
file = fopen("F:\\Uppgifter", "wb");
vinnare[0].ar = antalvinnareinlasning;
fwrite(&vinnare[0], sizeof(struct vinnare),1, file);
for (a = 1; a < (antalvinnareinlasning + 1); a++){
printf("Ange vilket år du vill mata in: ");
scanf("%d", &temp);
vinnare[a].ar = temp;
fflush(stdin);
printf("Ange vinnaren för det året:");
fgets(vinnare[a].namn, 20, stdin);
fflush(stdin);
fwrite(&vinnare[a], sizeof(struct vinnare), 1, file);
}
}
For the first block of struct data, you wrote:
fwrite(&vinnare[0], sizeof(struct vinnare),1, file);
i.e. sizeof(struct vinnare) bytes of data
but you are reading only int
fread(&antalvinnareinlasning, sizeof(int), 1, file);
i.e. 4 bytes of data
therefore the file pointer is advanced only by 4 bytes and points to 20 bytes of garbage data, which is then followed by next blocks of data that you wrote using for in function inlasningTillFil.
Here:
vinnare = inlasningTillFil(vinnare, antalvinnareinlasning);
You are assigning the value of a function that doesn't returns anything
I seriously doubt this for loop. You are starting from 1, means second item and ending with number_of_allocations + 1, clearly out of your allocations.
for (a = 1; a < (antalvinnareinlasning + 1); a++){
This is got me pretty stuck, how do I fix this? I know I haven't got error checking, but they aren't required i'd guess since it's restricted to my desktop. It obveously can't be EOF. It's for the infoheader struct, fileheader works fine. Do i need to take a new line or something?
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
unsigned char fileMarker1; /* 'B' */
unsigned char fileMarker2; /* 'M' */
unsigned int bfSize;
unsigned short unused1;
unsigned short unused2;
unsigned int imageDataOffset; /* Offset to the start of image data */
}FILEHEADER;
typedef struct
{
unsigned int biSize;
int width; /* Width of the image */
int height; /* Height of the image */
unsigned short planes;
unsigned short bitPix;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
}INFOHEADER;
typedef struct
{
unsigned char b; /* Blue value */
unsigned char g; /* Green value */
unsigned char r; /* Red value */
}IMAGECOMPONENT;
int fileheadfunc(FILE *image);
int infoheadfunc(FILE *image);
int main( int argc, char *argv[] )
{
char *filename; /* *threshholdInput = argv[2]; */
FILE *image;
int filehead, infohead;
filename = argv[1];
/* int threshhold = atoi(threshholdInput); */
if (argc != 2)
{
printf(" Incorrect Number Of Command Line Arguments\n");
return(0);
}
image = fopen( filename, "r");
if (image == NULL)
{
fprintf(stderr, "Error, cannot find file %s\n", filename);
exit(1);
}
filehead = fileheadfunc(image);
infohead = infoheadfunc(image);
fclose(image);
return(0);
}
int fileheadfunc(FILE *image)
{
FILEHEADER *header;
long pos;
fseek (image , 0 , SEEK_SET);
fread( (unsigned char*)header, sizeof(FILEHEADER), 1, image );
if ( (*header).fileMarker1 != 'B' || (*header).fileMarker2 != 'M' )
{
fprintf(stderr, "Incorrect file format");
exit(1);
}
printf("This is a bitmap!\n");
pos = ftell(image);
printf("%ld\n", pos);
printf("%zu\n", sizeof(FILEHEADER));
return(0);
}
int infoheadfunc(FILE *image)
{
INFOHEADER *iheader;
fseek (image, 0, SEEK_CUR );
fread( (unsigned int*)iheader, sizeof(INFOHEADER), 1, image );
printf("Width: %i\n", (*iheader).width);
printf("Height: %i\n", (*iheader).height);
return(0);
}
You're not actually allocating any storage for the BMP header data structures, e.g. you need to change this:
int fileheadfunc(FILE *image)
{
FILEHEADER *header;
long pos;
fseek(image, 0, SEEK_SET);
fread((unsigned char*)header, sizeof(FILEHEADER), 1, image);
...
to this:
int fileheadfunc(FILE *image)
{
FILEHEADER header; // <<<
long pos;
fseek(image, 0, SEEK_SET);
fread(&header, sizeof(FILEHEADER), 1, image); // <<<
...
Also, as previously noted in one of the comments above, you need #pragma pack(1) (or equivalent if you're not using gcc or a gcc-compatible compiler) prior to your struct definitions to eliminate unwanted padding. (NB: use #pragma pack() after your struct definitions to restore normal struct padding/alignment.)
There are two problems with the code:
Alignment
For performance reasons the compiler will, unless instructed to do otherwise, arrange struct fields on its "natural boundaries", effectively leaving uninitialised gaps between byte-size fields. Add
#pragma pack(1)
before the struct definitions and you should be fine. It's also easy to test: just print out the struct size without and with pragma pack in place, and you'll see the difference.
Allocation
As Paul R already said, you should allocate space for the headers, not just provide a pointer to the structures. The fact that fileheadfunc works is a coincidence, there just wasn't anything in the way that got smashed when data got written outside of the allocated space.
A last one, just for prevention sake: should you ever want to return the read structures to the calling program, do not just return a pointer to the structure allocated in the function as that will cause problems similat to the unallocated variables you have now. Allocate them in the calling function, and pass a pointer to that variable to the header read functions.
EDIT clarification regarding the last point:
DON'T
FILEHEADER * fileheadfunc(FILE *image)
{
FILEHEADER header;
...
return &header; // returns an address on the function stack that will
// disappear once you return
}
DO
int fileheadfunc(FILE *image, FILEHEADER *header)
{
...
}
which will be called like this
...
FILEHEADER header;
returnvalue = fileheaderfunc(imagefile,&header);
EDIT2: just noticed that the way you read the DIB header is not correct. There are several variations of that header, with different sizes. So after reading the file header you first need to read 4 bytes into an unsigned int and based on the value read select the correct DIB header structure to use (don't forget you already read its first field!) or tell the user you encountered an unsupported file format.