Hey everyone. Glad to become part of this community and I hope I continue to come here for a long time seeing as this site gives great helps. My problem:

I have a struct that is (for example) the following:

#define NUM 999

struct client
		{
                        int id;
			char name[15]; 
			char lastname[15]; 
			int telephone; 
}c[NUM];

I want to do the following: First I want to see if the file exists or not. Thats pretty simple using a pointer to the fopen function with the file; If it returns NULL it doesnt exist. Now the hard part is reading and loading and then after saving.

If it isnt found, all the struct will be set to the number/string 0. If its found, then all of the data from the text file is loaded onto the struct and I work with the struct modifing, deleteing, adding, etc.
At the end of the program when I hit enter, Id like for the program to save all (or the changes) to the text file so when I load the program again it has all the additions I previously made.

If Im not clear on something, go ahead and ask. Thank you very much for your help.

Recommended Answers

All 14 Replies

> If Im not clear on something, go ahead and ask.
What is it you want? Edward prefers to see the best in others, but if you only post the requirements of your program, at least one person is going to think you want it all written for you.

It's best to post your current attempt and ask for specific help about the code or the design. Then it's easy to see that you're just having a little trouble and not looking for a free ride. :) You'll also get better help because people like Ed can focus on the trouble areas and ignore the areas that you've got covered.

So first you open it, then you read it in, parse the file in your structure, and move on to the next.

Reading in a file: fread()
Parsing: Your own mix and a bit of sscanf();

writing would be exactly the opposite: sprintf() and fwrite().

sprintf and sscanf work like printf and scanf, except the first argument is a pointer to a character array which is read from/printed to.

Id like to post the code but its in spanish so it wouldnt help much.

I tried just making a typedef with a *cl but the problem is I cant go thru each 999 of the clients (c[num]). What Id like to do is point the *cl pointer to c[num] and somehow run thru it such as *cl[num] (I know a array is already a pointer so it wont work.)

If there is any part that I could describe so someone can help me, just say.

You really oughta post some of the code here. I'm sure most people here have dealt with oddly name variables.

OK here's the code for my structs:

#define num 999 // Para que sean todos las estructuras de 999

/* Estructuras principales */
struct direccion
		{
			char calle[15]; //Limitado a 15 characteres
			int numportal; //1 digito
			int piso; //1 digito
}; 
struct poblacion
		{
			char nombrepoblacion[15]; //Limitado a 15 characteres
			int codpostal; //Limitado a 5 digitos
			char provincia[15]; //Limitado a 15 characteres
}; 

struct empleados
{
	int id; // Limitado a una letra E seguido de 3 numeros
	char dni[11]; //Limitado a 8 numeros, un guion y una letra
	char nombre[15]; //Limitado a 15 characteres
	char apellido[15]; //Limitado a 15 characteres
	int telefono; //Limitado a 9 digitos
	struct direccion dir; // Una variable que es de tipo estructura dirrecion: acesso a calle,
						  //Numportal, y piso
	struct poblacion pob; // Una variable que es de tipo estructura poblacion: accesso a
						  // nombrepoblacion, codpostal, y provincia
}e[num]; 
/* Asi podemos insertar hasta 999 productos, porque he creado 
la tabla que contiene num elementos de tipo empleados: Este numero es el mismo que el id */



struct clientes
{
	int id; // Limitado a una letra C seguido de 3 numeros
	char dni[11]; //Limitado a 8 numeros, un espacio y una letra
	char nombre[15];//Limitado a 15 characteres
	char apellido[15];//Limitado a 15 characteres
	int telefono;//Limitado a 6 digitos
	struct direccion dir; // Una variable que es de tipo estructura dirrecion: acesso a calle,
						  //Numportal, y piso
	struct poblacion pob; // Una variable que es de tipo estructura poblacion: accesso a
						  // nombrepoblacion, codpostal, y provincia
	int cantcompras; // La cantidad de comprars para los descuentos

}c[num]; 
/* Asi podemos insertar hasta 999 productos, porque he creado 
la tabla que contiene num elementos de tipo cliente: Este numero es el mismo que el id */




struct productos
{
	
	int id; // Limitado a una letra P seguido de 3 numeros
	char nombre[15]; //Limitado a 15 characteres
	char descripcion[50]; //Limitado a 50 characteres
	float precio; // Precio con decimal
	int cantidad; //Lo que queda en stock

}p[num]; 
/* Asi podemos insertar hasta 999 productos, porque he creado 
la tabla que contiene num elementos de tipo producto: Este numero es el mismo que el id */

Ill explain:

p is a variable that I can use to access each field. It is a array so I can access all 999 possible clients in the struct (why? explanation below:)

void inicializar ()
{ // Principio de funciones inicizalizar
	int a=0; // 1 Contador

	/********************* Inicializamos la estructura de clientes *************************/
	/* Campos int id, char dni, char nombre, char apellido, int telefono */
	
	
	for (a=0;a<999;a++) 
	{
		
		c[a].id=0;
		strcpy(c[a].dni,"0");
		strcpy(c[a].nombre,"0");
		strcpy(c[a].apellido,"0");
		c[a].telefono=0;
		c[a].cantcompras=0;
		strcpy(c[a].dir.calle,"0");
		c[a].dir.numportal=0;
		c[a].dir.piso=0;
		c[a].pob.codpostal=0;
		strcpy(c[a].pob.nombrepoblacion,"0");
		strcpy(c[a].pob.provincia,"0");
	}
	/***************** Fin de inicializacion de clientes ******************************/


	/********************* Inicializamos la estructura de empleados *************************/
	/* Campos: int id, char dni, char nombre, char apellido, int telefono */

	for (a=0;a<999;a++) 
	{
		
		e[a].id=0;
		strcpy(e[a].dni,"0");
		strcpy(e[a].nombre,"0");
		strcpy(e[a].apellido,"0");
		e[a].telefono=0;
		strcpy(e[a].dir.calle,"0");
		e[a].dir.numportal=0;
		e[a].dir.piso=0;
		e[a].pob.codpostal=0;
		strcpy(e[a].pob.nombrepoblacion,"0");
		strcpy(e[a].pob.provincia,"0");
	
		
	}
	/********************* Fin de inicializacion de empleados ******************************/
	

	


	/***************** Inicializamos la estructura de productos ***********************/

	for (a=0;a<999;a++) // Este for permite que cada 999 de los productos lo ponga a 0
	{
	p[a].id=0;
	strcpy(p[a].nombre,"0");
	strcpy(p[a].descripcion,"0");
	p[a].precio=0.0;
	p[a].cantidad=0;
	}

	/***************** Fin de inicializacion de productos ******************************/

} // Fin de funciones de inicializar

As you can see I set here all values to 0. Why? Because I use 0 or "0" as a wildcard for some function to see if the client's empty or not.

The point is that I have to do all of this (add,modify,delete,etc) using a pointer that acceses a file instead of setting it values. In this file, I should have all of the fields and everytime I load the program it sets the values in the file to the struct. I work locally with the struct and when I end the program it saves all of it to a file. I have this so far:

void inicializarporarchivo()
{
	FILE *ficheroc;
	FILE *ficheroe;
	FILE *ficherop;
	int i;
	char tid[1];
	char ttelefono[9];
	char tcantcompras[1];
	char tnumportal[2];
	char tpiso[1];

	ficheroc=fopen("clientes.txt","r");
	ficheroe=fopen("empleados.txt","r");
	ficherop=fopen("productos.txt","r");
	if (ficheroc==NULL)
	{
		void inicializar();
	}
	
	/*	fclose(ficheroc);
		ficheroc=fopen("clientes.txt","w");
		for (i=0;i<999;i++)
		{
			fputs("Cliente ",ficheroc);
			fputc(i,ficheroc);
			fputs(":",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputc("0",ficheroc);
			fputs("\n",ficheroc);
		}*/

	if (ficheroc!=NULL)
	{
		do
		{
			for (i=0;i<999;i++)
			{
			fgets(tid,sizeof(tid),ficheroc);
			c[i].id=atoi(tid);
			fgets(c[i].dni,sizeof(c[i].dni),ficheroc);
			fgets(c[i].nombre,sizeof(c[i].nombre),ficheroc);
			fgets(c[i].apellido,sizeof(c[i].apellido),ficheroc);
			fgets(ttelefono,sizeof(ttelefono),ficheroc);
			c[i].telefono=atoi(ttelefono);
			fgets(tcantcompras,sizeof(tcantcompras),ficheroc);
			c[i].cantcompras=atoi(tcantcompras);
			fgets(c[i].dir.calle,sizeof(c[i].dir.calle),ficheroc);
			fgets(tnumportal,sizeof(tnumportal),ficheroc);
			c[i].dir.numportal=atoi(tnumportal);
			fgets(tpiso,sizeof(tpiso),ficheroc);
			c[i].dir.piso=atoi(tpiso);
			fgets(c[i].dir.calle,sizeof(c[i].dir.calle),ficheroc);
			fgets(c[i].pob.nombrepoblacion,sizeof(c[i].pob.nombrepoblacion),ficheroc);
			fgets(c[i].pob.provincia,sizeof(c[i].pob.provincia),ficheroc);
			printf ("%s",c[i].dni);
			getch();
			}
			putc("\0",ficheroc);
		}while (feof(ficheroc)!=1);
	}
		
}

But it doesnt work nor does it use a pointer.
Objectives:

1: Use a pointer to access the data in each field.
2: Load/save from/to a file.

in inicializar():
I wouldn't initialize strings like that. Better to use memset to clear them, or only set the first byte to the NULL byte. Doesn't really matter, but it makes the code a bit more readable. I think.

in inicializarporarchivo:
char tid[1];
char ttelefono[9];
char tcantcompras[1];
char tnumportal[2];
char tpiso[1];

tid, tcantcompras, tpiso: char arrays of a single char?

How do your files look? Your only using fgets, which reads in a file until it encounters a '\n'. Is that correct?

You're trying to use putc on a file which you opened as "r"eadonly. That' can't be correct.

You're testing "feof()" with "!= 1". Better would it be to continue when "feof == 0", since TRUE isn't defined as 1 but as any non-zero number.

in inicializar():Better to use memset to clear them, or only set the first byte to the NULL byte.

I havent read anythning about that so that isnt a option

in inicializarporarchivo:
char tid[1];
char ttelefono[9];
char tcantcompras[1];
char tnumportal[2];
char tpiso[1];

tid, tcantcompras, tpiso: char arrays of a single char?

Yes that was kind of stupid because I was stressed.

How do your files look? Your only using fgets, which reads in a file until it encounters a '\n'. Is that correct?

I dont understand this very well but my files are like this:

Client 1:
1234567-L
David
James

So each line (\n) is read and inserted into each field in the struct. Is that the correct way to do it?

You're trying to use putc on a file which you opened as "r"eadonly. That' can't be correct.

I dont use putc in anywhere...except maybe when it is NULL and it has to close and open it as write...

You're testing "feof()" with "!= 1". Better would it be to continue when "feof == 0", since TRUE isn't defined as 1 but as any non-zero number.

Reexplain this please.

If you need to reopen it for writing, why don't you open it for reading and writing "rw" or reopen it with freopen()?

feof() returns a nonzero value when the FILE* has reached the EOF. Your while-loop checks if it doesn't equal one, but it should check if it equals 0: it may not return 1, it may return any nonzero number. This doesn't have to be a problem, but it's more secure.

If you haven't read anything about memset, you don't know how to initialize arrays. Which is kinda bad. You can set the whole c[], p[] and other arrays to 0 or any value you prefer with memset. Read up on it. It'd make the program more readable and faster.

By the way, here's a nice reference:
c(pp)reference

If you need to reopen it for writing, why don't you open it for reading and writing "rw" or reopen it with freopen()?

Because Ive been show that its more secure to open and close it....
Don't know about freopen.

feof() returns a nonzero value when the FILE has reached the EOF. Your while-loop checks if it doesn't equal one, but it should check if it equals 0: it may not return 1, it may return any nonzero number. This doesn't have to be a problem, but it's more secure.

I understand and Ill fix this :)

If you haven't read anything about memset, you don't know how to initialize arrays. Which is kinda bad. You can set the whole c[], p[] and other arrays to 0 or any value you prefer with memset. Read up on it. It'd make the program more readable and faster.

Well to initialize a array we weren't shown using memset....

By the way, here's a nice reference:
http://www.cppreference.com/index.html

Thanks.

Thanks BTW for all your help Clockowl. :)

I have another question but related.

As you see I have

c[num] for my structs.
How can I use a pointer to go thru all 999 positions for the struct? Pointers and file handling are my weakpoints; Any more pages about these subjects would be great. Again thanks Clockowl

Well, i think you are increasing your problem a lot, remember that a struct look in the "computer way" is just like an array, or a matrx, "a conjunt of bytes", so, you may use fread to retrieve all data from your file:

fread(&myStructInstance, sizeof(MyStruct), totalElements, myFilePtr);

no matter how many elements you have in your struct, nor the total amount of tupples on your file, fread will try to fill your structure instance as with many data as he can get from the stream.

since you can get/store the information, (store is with fwrite at the same way) you may use a pointer of type of your structure to walk on every struct elements:

struct *myStructPtr;
myStructPtr = myStructInstance;
for (i =0; i<999;i++) {
/* Use mystructptr with the arrow operand (->) */
}

Maybe you should abstract the ideas for retrieving and storing data into a different file, you you can reuse those code in handling all your structures

Hope it helps

P.D. To proper use fread and fwrite you need to open your file in binary mode (just add an "b" to the "opening flags"

C does all your pointermath for you. If you create a pointer to a structure and then increment it, it adds sizeof(structure) bytes to the pointer.

For example:
When an array is declared, the name of the array without element brackets is a pointer to the first element.

struct productos *productPointer = p;

after this, p[1] is the same element as *(productPointer + 1), p[2] == *(productPointer + 2), etc.
However, it's often easier not to dereference the pointer like that, instead use the arrow operator. This operator sees the previous variable as a pointer to a structure.
p[1].precio is the same as (productPointer + 1)->precio.

you can also change productPointer itself with increments and decrements. Just rememeber that you are not incrementing in bytes, but in sizes of the type you're pointing to. In this case, that's sizeof(struct productos).

fread doesn't need "b" to my experience, nor does it say so on all of the reference sites I consult. Don't worry about it.

Well, i think you are increasing your problem a lot, remember that a struct look in the "computer way" is just like an array, or a matrx, "a conjunt of bytes", so, you may use fread to retrieve all data from your file:

fread(&myStructInstance, sizeof(MyStruct), totalElements, myFilePtr);

no matter how many elements you have in your struct, nor the total amount of tupples on your file, fread will try to fill your structure instance as with many data as he can get from the stream.

since you can get/store the information, (store is with fwrite at the same way) you may use a pointer of type of your structure to walk on every struct elements:

struct *myStructPtr;
myStructPtr = myStructInstance;
for (i =0; i<999;i++) {
/* Use mystructptr with the arrow operand (->) */
}

Maybe you should abstract the ideas for retrieving and storing data into a different file, you you can reuse those code in handling all your structures

Hope it helps

P.D. To proper use fread and fwrite you need to open your file in binary mode (just add an "b" to the "opening flags"

Like I said, I havent been informed about the fread function so I dont think ill be using something that I have to read about and learn quickly to implant it.

Describe this code a bit better:

struct *myStructPtr;
myStructPtr = myStructInstance;
for (i =0; i<999;i++) {
  /* Use mystructptr with the arrow operand (->) */
}

struct *myStructPtr; = I understand from that line that you have a structure named "*mystructptr" or you are declaring a pointer that points to a variable of type "struct"

myStructPtr points to myStructInstance......???

And the for is self explains :)

Can anyone explain the code please?

I've already explained it. The bold part.

C does all your pointermath for you. If you create a pointer to a structure and then increment it, it adds sizeof(structure) bytes to the pointer.

For example:
When an array is declared, the name of the array without element brackets is a pointer to the first element.

struct productos *productPointer = p;

after this, p[1] is the same element as *(productPointer + 1), p[2] == *(productPointer + 2), etc.
However, it's often easier not to dereference the pointer like that, instead use the arrow operator. This operator sees the previous variable as a pointer to a structure.
p[1].precio is the same as (productPointer + 1)->precio.

you can also change productPointer itself with increments and decrements. Just rememeber that you are not incrementing in bytes, but in sizes of the type you're pointing to. In this case, that's sizeof(struct productos).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.