FILE I/O operations. Clearing the elements of an structure - c

I'm a begginer but I'm basically creating a program that opens a binary file containing 'parts' structure, reads the structure
into an array, sets the on_hand member of each structure to 0, and then writes the structure back to the file. Here's my code:
invclear.c
/* Modifies a file of part records by setting the quantity
on hand to a zero for all records */
#include <stdio.h>
#include <stdlib.h>
#define NAME_LEN 25
#define MAX_PARTS 100
struct part { //size= 36 bytes (2 holes in between number and name[] array
int number;
char name[NAME_LEN+1];
int on_hand;
}inventory[MAX_PARTS];
int num_parts;
int main()
{
FILE *fp;
int i;
if((fp=fopen("clear_sample.c", "rb+")) == NULL)
{
fprintf(stderr, "Can't open inventory file.\n");
exit(EXIT_FAILURE);
}
num_parts = fread(inventory, sizeof(struct part), MAX_PARTS, fp); //reads the contents
for(i=0; i<num_parts; i++)
inventory[i].on_hand=0; //clears them
rewind(fp); //sets file position at beggining
fwrite(inventory,sizeof(struct part), num_parts, fp);
fclose(fp);
return 0;
}
clear_sample.c
#include <stdio.h>
#include <stdlib.h>
#define NAME_LEN 25
#define MAX_PARTS 100
struct part {
int number;
char name[NAME_LEN+1];
int on_hand;
}inventory[MAX_PARTS]={0};
int main()
{
int i;
int num_parts;
for(i=1;i<=15;i++)
inventory[i].on_hand=i;
for(i=1;i<=15;i++)
printf("%d\n",inventory[i].on_hand);
return 0;
}
It runs without errors but unfortunately it's not clearing the on_hand variable to 0, in fact it's deleting almost the whole file. This is the modified clear_sample.c file that I get:
#include <stdio.h>
#include <st
Any ideas into why am I doing wrong would be greatly appreciated.

You have been misled by whatever tool you used to inspect the resulting file. It is not
#include <stdio.h>
#include <st
In fact it is
#include <stdio.h>
#include <std^#^#^#^#h>
#define NAME_LEN 25
#define ^#^#^#^#PARTS 100
struct part {
int^#^#^#^#ber;
char name[NAME_LEN+1];
^#^#^#^#int on_hand;
}inventory[MAX_^#^#^#^#S]={0};
int main()
{
int i^#^#^#^# int num_parts;
for(i=1;i<^#^#^#^#i++)
inventory[i].on_han^#^#^#^#
for(i=1;i<=15;i++)
^#^#^#^#ntf("%d\n",inventory[i].on_hand)^#^#^#^# return 0;
}
All those ^# are binary zero bytes, corresponding to zeroes you've put into on_hand.
As mentioned in comments, to test your program prepare a file which does obey the format you expect.

Related

How do you assign structs into an array?

I have currently made this much of the code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#define STRSIZE 21
struct PInven{
int count;
struct PItem{
char name[STRSIZE];
int amount;
}Pitem;
}Pinven;//this needs to be an output file
int ReadInProduce (){
//read in file and check to see if the file exist or not.
FILE * PinFile = fopen("produce.txt","r");
if (PinFile == NULL){
printf("ERROR: WRONG FILE");
}
else{
printf("I did it!!\n");
}
//assigning the value gotten into the struct variable(but need to maybe change this since it needs to be an output)
fscanf(PinFile,"%d",&Pinven.count);
printf("%d\n", Pinven.count);
int i;
for(i =0; i <Pinven.count; i++){
fscanf(PinFile,"%20s %d",Pinven.Pitem.name, &Pinven.Pitem.amount);
printf("%s %d\n",Pinven.Pitem.name, Pinven.Pitem.amount);
}
//making an array to hold the variables
//FILE * PoutFile = fopen("produce_update.txt","w");
fclose(PinFile);
return 0;
}
From there I want to get the file that is read to the structs to be printed out into an array so that later on I can make a function that will be able to compare to the to it.
Basically a store management system. Where the file of the inventory is read in and compared to the file that is store and return a new value for the amount of produce now either left or gained.
10 //number of items that will be stored in the store
apple 19
banana 31
broccoli 9
...
In general, it's a really bad idea to include header information in the file about the number of entries in the file. You want to be able to do stream processing, and that will be more difficult if you need that meta-data. More importantly, it is important to understand how to write the code so that you don't need it. It's not really that difficult, but for some reason people avoid it. One simple approach is just to grow the array for each entry. This is horribly inefficient, but for the sake of simplicity, here's an example that expects the file not not include that first line:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <limits.h>
#define STRSIZE 128
struct PItem{
char name[STRSIZE];
int amount;
};
struct PInven{
int count;
struct PItem *PItem;
};
static void
grow(struct PInven *p)
{
p->PItem = realloc(p->PItem, ++p->count * sizeof *p->PItem);
if( p->PItem == NULL ){
perror("out of memory");
exit(1);
}
}
int
ReadInProduce(struct PInven *P, const char *path)
{
FILE * PinFile = fopen(path, "r");
if( PinFile == NULL ){
perror(path);
exit(1);
}
char fmt[64];
int max_len;
max_len = snprintf(fmt, 0, "%d", INT_MAX);
snprintf(fmt, sizeof fmt, "%%%ds %%%dd", STRSIZE - 1, max_len - 1);
grow(P);
struct PItem *i = P->PItem;
while( fscanf(PinFile, fmt, i->name, &i->amount) == 2 ){
i += 1;
grow(P);
}
P->count -= 1;
fclose(PinFile); /* Should check for error here! */
return P->count;
}
int
main(int argc, char **argv)
{
struct PInven P = {0};
char *input = argc > 1 ? argv[1] : "produce.txt";
ReadInProduce(&P, input);
struct PItem *t = P.PItem;
for( int i = 0; i < P.count; i++, t++ ){
printf("%10d: %s\n", t->amount, t->name);
}
}
As an exercise for the reader, you should add some error handling. At the moment, this code simply stops reading the input file if there is bad input. Also, it would be a useful exercise to do fewer reallocations.
you should change Structure of PInven to it can save a dynamic array of Pitem with a Pitem pointer.
tested :
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define STRSIZE 21
typedef struct {
char name[STRSIZE];
int amount;
} Pitem;
struct PInven {
int count;
Pitem *pitem;
} Pinven; // this needs to be an output file
int main() {
// read in file and check to see if the file exist or not.
FILE *PinFile = fopen("produce.txt", "r");
if (PinFile == NULL) {
printf("ERROR: WRONG FILE");
} else {
printf("I did it!!\n");
}
// assigning the value gotten into the struct variable(but need to maybe
// change this since it needs to be an output)
fscanf(PinFile, "%d", &Pinven.count);
Pinven.pitem = (Pitem *)malloc(sizeof(Pitem) * Pinven.count);
printf("%d\n", Pinven.count);
int i;
for (i = 0; i < Pinven.count; i++) {
fscanf(PinFile, "%20s %d", Pinven.pitem[i].name,
&Pinven.pitem[i].amount);
// printf("%s %d\n",Pinven.pitem[i].name, Pinven.pitem[i].amount);
}
for (i = 0; i < Pinven.count; i++) {
printf("%s %d\n", Pinven.pitem[i].name, Pinven.pitem[i].amount);
}
// making an array to hold the variables
// FILE * PoutFile = fopen("produce_update.txt","w");
fclose(PinFile);
// remember free
free(Pinven.pitem);
return 0;
}

Structures Program not working as intended (Bug)

I have been working on reading data from a file, which contains student name and age in the format:
John
12
Jane
13
Julia
18
Here's the program I wrote:
#include <stdio.h>
#include <stdlib.h>
struct record{
char name[50];
int age;
};
int main(){
FILE *fp;
fp=fopen("sample2.txt","r");
struct record a[50];
int counter=1;
int i=0;
while (!EOF){
if (counter%2!=0){
fgets(a[i].name,50,fp);
counter++;
}
if (counter%2==0){
a[i].age=getw(fp);
counter++;
i++;
}
}
return 0;
}
However, on printing a[0].name, I am not getting expected output. Can someone help?
As already pointed out in the comments, EOF is a value defined in stdio.h and does not say anything about your file descriptor. I also would recommend you to use fscanf (As long you are sure that the names in the file are all of the correct length). fscanf takes a string similar to printf, specifying the elements you are expecting and returns the number of possible matches. Also it helps you with converting your data to the correct datatypes. So the code could look like this:
#include <stdio.h>
#include <stdlib.h>
struct record
{
char name[50];
int age;
};
int main ()
{
FILE *fp;
fp = fopen ("sample2.txt", "r");
struct record a[50];
int i = 0;
while (fscanf(fp, "%s\n%d\n", (char *) a[i].name, &a[i].age) > 0) {
i++;
}
printf("%s %d\n", a[1].name, a[1].age);
return 0;
}

how to use qsort in C to sort struct array?

I have a problem in my programming, I totally have no idea why I cannot use qsort in my program to sort these struct array in an ordered way? Can some way help me? in this program, there are 4 Nodes, and the every node represent a file, the node has filename, size and filetype. I want to sort it based on filename, but I totally have no idea why qsort doesn't work at all!
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
//int cmp(const void *a,const void*b);
typedef struct node
{
char filename[255];
char filetype[255];
long ofilesize;
long newfilesize;
}Node;
Node Line[4];
int cmp(const void *a,const void*b)
{
return strcmp(((Node *)a)->filename,((Node *)b)->filename);
}
int main(){
/* int j=0;
for(;j<4;j++){
Line[j]=(Node*)malloc(sizeof(Node));
}*/
strcpy(Line[0].filename,"b.txt");
strcpy(Line[1].filename,"c.txt");
strcpy(Line[2].filename,"d.txt");
strcpy(Line[3].filename,"e.txt");
int i=0;
for(;i<4;i++){
strcpy(Line[i].filetype,"regular file");
Line[i].ofilesize=i;
Line[i].newfilesize=i;
}
for(i=0;i<4;i++)
{
printf("File %s has type %s original size %ld new size %ld \n",Line[i].filename,Line[i].filetype,Line[i].ofilesize,Line[i].newfilesize);
}
qsort((void *)&Line,4,sizeof(Node),cmp);
for(i=0;i<4;i++)
{
printf("File %s has type %s original size %ld new size %ld \n",Line[i].filename,Line[i].filetype,Line[i].ofilesize,Line[i].newfilesize);
}
}
here is my output:
File b.txt has type regular file original size 0 new size 0
File c.txt has type regular file original size 1 new size 1
File d.txt has type regular file original size 2 new size 2
File e.txt has type regular file original size 3 new size 3
File b.txt has type regular file original size 0 new size 0
File c.txt has type regular file original size 1 new size 1
File d.txt has type regular file original size 2 new size 2
File e.txt has type regular file original size 3 new size 3
What the author of the comment that got deleted said was
int cmp(Node *a,Node *b) {
return strcmp(a->filename,b->filename);
}
should be
int cmp(Node **a,Node **b) {
return strcmp((*a)->filename,(*b)->filename);
}
if you want to keep your pointers.
This is very easy to solve using C++11. Let the compiler handle the memory allocations for you, and avoid all those nasty pointers.
#include <array>
#include <string>
#include <algorithm>
struct Node
{
std::string filename;
std::string filetype;
long ofilesize;
long newfilesize;
};
bool CompareByFilename(const Node& lhs, const Node& rhs)
{
return lhs.filename < rhs.filename;
}
int main()
{
std::array<Node, 4> line;
line[0].filename = "e.txt";
line[1].filename = "d.txt";
line[2].filename = "c.txt";
line[3].filename = "b.txt";
for (unsigned int i = 0; i < line.size(); i++)
{
line[i].filetype = "regular file";
line[i].ofilesize = i;
line[i].newfilesize = i;
}
std::sort(line.begin(), line.end(), CompareByFilename);
}
Consider using an enum for the file type, and are you sure long is always going to be big enough to hold the file size?

Counting different words from a text input

I want to do a code that searches a txt file and returns the number of different words and how many times they appear on the text.
I' trying to do that, but I'm having a problem on comparing the word read from the input with the words already read. So I'm doing a code that adds a word to the vector of words if is new, and if it isn't, it increments by 1 the word count. But when I'm comparing the words, it doesn't states that they're equal even when they aren't.
By exemple: txt is filled with:
test test test.
test test test.
("test." =/= from "test"). And it return 7 different words with 3 being NULL, "3 test" and 1 "test." . That should return 2 words and count 4 on test and count 2 on test.
Can anybody see what is wrong with my code?
#define MAX_PALAVRAS 1024
#define MAX_TAM_PALAVRA 32
typedef struct ocorrencia_ {
char palavra[MAX_TAM_PALAVRA];
int pos;
int num_ocorrencias;
}ocorrencia;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
int main (int argc, char * argv[]){
ocorrencia palavras[MAX_PALAVRAS];
int i,palavras_diferentes=0,palavra_atual=0;
char aux[MAX_TAM_PALAVRA];
bool nova_palavra=true;
for (i=0;i<MAX_PALAVRAS;i++){
palavras[i].pos=-1;
palavras[i].num_ocorrencias=0;
}
FILE * D = fopen("input.txt","r");
while (!feof(D)){
char aux2[MAX_TAM_PALAVRA];
fscanf(D,"%s",aux);
for (i=0;i<palavras_diferentes;i++){
if (strcmp(palavras[palavras_diferentes].palavra,aux)==0){
nova_palavra=false;
break;
}
palavra_atual++;
}
if (nova_palavra){
strcpy(palavras[palavra_atual].palavra,aux);
palavras_diferentes++;
}
palavras[palavra_atual].num_ocorrencias++;
printf("%s\n",palavras[palavra_atual].palavra);
}
fclose (D);
printf("diferent words=%i\n",palavras_diferentes);
printf("success!\n");
return (EXIT_SUCCESS);
}
Thanks for taking or time reading or trying to help!
Following my comments, here are a few changes that may help you :
-Set palavra_atual to 0 and nova_palavra to true at the beginning of the while loop.
-Test the return of fscanf, add something like if(fscanf(D,"%s",aux)==1){...}
-Test all words ! if (strcmp(palavras[i].palavra,aux)==0)
Here goes the code :
#define MAX_PALAVRAS 1024
#define MAX_TAM_PALAVRA 32
typedef struct ocorrencia_ {
char palavra[MAX_TAM_PALAVRA];
int pos;
int num_ocorrencias;
}ocorrencia;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
int main (int argc, char * argv[]){
ocorrencia palavras[MAX_PALAVRAS];
int i,palavras_diferentes=0,palavra_atual=0;
char aux[MAX_TAM_PALAVRA];
bool nova_palavra=true;
for (i=0;i<MAX_PALAVRAS;i++){
palavras[i].pos=-1;
palavras[i].num_ocorrencias=0;
}
FILE * D = fopen("input.txt","r");
while (!feof(D)){
palavra_atual=0;
nova_palavra=true;
char aux2[MAX_TAM_PALAVRA];
if(fscanf(D,"%s",aux)==1){
for (i=0;i<palavras_diferentes;i++){
if (strcmp(palavras[i].palavra,aux)==0){
nova_palavra=false;
break;
}
palavra_atual++;
}
if (nova_palavra==true){
printf("new word %d %s\n",palavra_atual,aux);
strcpy(palavras[palavra_atual].palavra,aux);
palavras_diferentes++;
}
palavras[palavra_atual].num_ocorrencias++;
printf("%s\n",palavras[palavra_atual].palavra);
}
}
fclose (D);
printf("diferent words=%i\n",palavras_diferentes);
printf("success!\n");
return (EXIT_SUCCESS);
}
You will be interesseted by ispunct() of ctypes.h here

c fwrite() writing to a file with only one of the struct variable?

This function is supposed to get a parameter as the pointer of a file and put all file into the struct anagram, then write it to another file. Right now the data only contains a.word, but it suppose to containst a.sorted too? I have check the a.sorted using printf
and it printf out the correct data, but why its not writing to the data file?
It still cant get the a.sorted even if i increase the count of the frwite
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "anagrams.h"
#define SIZE 80
//struct
struct anagram {
char word[SIZE];
char sorted[SIZE];
};
void buildDB ( const char *const dbFilename ){
FILE *dict, *anagramsFile;
struct anagram a;
//check if dict and anagram.data are open
errno=0;
dict= fopen(dbFilename, "r");
if(errno!=0) {
perror(dbFilename);
exit(1);
}
errno=0;
anagramsFile = fopen(anagramDB,"wb");
char word[SIZE];
char *pos;
int i=0;
while(fgets(word, SIZE, dict) !=NULL){
//get ripe of the '\n'
pos=strchr(word, '\n');
*pos = '\0';
strncpy(a.word,word,sizeof(word));
//lowercase word
int j=0;
while (word[j])
{
tolower(word[j]);
j++;
}
/* sort array using qsort functions */
qsort(word,strlen(word), 1, charCompare);
strncpy(a.sorted,word,sizeof(word));
//printf(a);
fwrite(&a,1,strlen(word)+1,anagramsFile);
i++;
}
fclose(dict);
fclose(anagramsFile);
}
it suppose to contains data with a.sorted for example "10th 01ht"
data:
fwrite(&a,1,strlen(word)+1,anagramsFile); should have been fwrite(a.sorted,1,strlen(a.sorted)+1,anagramsFile); I assume the declaration of sorted as char sorted[SOME_LEN];

Resources