Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Marks Programming Journey 13/?

0 views
Skip to first unread message

eda...@cts.com

unread,
Jun 30, 1995, 3:00:00 AM6/30/95
to
From the introduction:

This series has several purposes:
1) To help clarify things as I learn them
2) To have experienced programmers spot any errors and correct me before
it's too late. I mean errors not what makes for 'good' or 'bad'
code.
3) To help other beginners.

Please keep in mind that this is not a course and that it is likely that
there will be errors and inaccuracies. If you are an experienced
programmer and spot any errors please post them. If you are a beginner
like me, use a book written by a professional as I am doing.
--------------------------------------------------------------------------
It is possible to address structures with pointers. Pointers are declared
just as they are for pointers to other variable types:

struct person friend *pfriendd;

and their addresses are assigned likewise:

pfriend=&friend;

Accessing members is done differently. You have to use the '->' instead of
the '.'.

C has several time and date functions and variable types defined in
time.h. One of these is time_t. It is a variable type capable of holding
the system time in an encoded format specific to the system referred to as
'calendar time'. To obtain calendar time use the function:

time_t time(time_t *time);

It return a -1 if it isn't available. It also places it into the variable
pointed to by *time. If *time is null it is ignored.

There are some functions that convert calendar time into something more
usefully. One of these is:

struct tm *localtime(time_t *time);

It returns a pointer to a structure defined in time.h called tm:

struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_istst;
}

localtime() creates a instance of tm and returns a pointer to it.

The exercise was to rewrite an example so that it also displays GMT.
There is a function that works just like localtime() except it does it for
GMT. Here it is:


#include <time.h>
#include <stdio.h>
main(int argc, char *argv[], char *envp[])
{
struct tm pactime, zulutime, *ppactime, *pzulutime;
time_t ctime, *pctime;

pctime=&ctime;
time(pctime);
ppactime=localtime(pctime);
pactime=*ppactime;
pzulutime=gmtime(pctime);
zulutime=*pzulutime;
printf("The time is %d:%d:%d %d-%d-%d local\n",
pactime.tm_hour,pactime.tm_min,pactime.tm_sec,pactime.tm_mon+1,
pactime.tm_mday,pactime.tm_year);
printf("The time is %d:%d:%d %d-%d-%d GMT\n",
zulutime.tm_hour,zulutime.tm_min,zulutime.tm_sec,zulutime.tm_mon+1,
zulutime.tm_mday,zulutime.tm_year);
printf("\nThis is the same thing done with pointers to structures.\n\n");

printf("The time is %d:%d:%d %d-%d-%d local\n",
ppactime->tm_hour,ppactime->tm_min,ppactime->tm_sec,
ppactime->tm_mon+1,ppactime->tm_mday,ppactime->tm_year);

printf("The time is %d:%d:%d %d-%d-%d GMT\n",
pzulutime->tm_hour,pzulutime->tm_min,pzulutime->tm_sec,
pzulutime->tm_mon+1,pzulutime->tm_mday,pzulutime->tm_year);

}

Nesting of structures is allowed.

struct st1{
int element1;
int element2;
};

struct st2{
int element;
struct st1 substructure;
}s;

To access a member in a nested structure use multiple '.'s

s.substructure.element1=7;

The exercise was to add a substructure to the phone list program that
contains addresses. This is it:


#include <stdio.h>
#include <conio.h>
#include <string.h>
#define MAX 100
void load(void);
void save(void);
void enter(void);
void find(void);
void all(void);
void change(void);
char file[40]="a:\\default.phn", *pfile;
FILE *datafile;
int index=0;
struct address
{char streetnum [10];
char street[40];
char apt [10];
char city[40];
char state[40];
char zip[20];
char country[40];
};

struct person
{
char name[40];
int areacode;
int phone;
struct address mail;
};

struct person people[MAX+1];
main(int argc, char *argv[], char *envp[])
{char option;
pfile = file;
if(argc==2) strcpy(file,argv[1]);
load();
strcpy(people[0].name,"none");
people[0].areacode=0;
people[0].phone=0;
while(option!='X')
{printf("Do you want to [L]oad [S]ave [E]nter [F]ind an entry ");
printf("list [A]ll entries e[X]it\n");
option=toupper(getch());
switch(option)
{
case 'A':
all();
break;
case 'E':
enter();
break;
case 'F':
find();
break;
case 'S':
save();
break;
case 'C':
change();
break;
case 'L':
load();
break;
}
}
}
void enter(void)
{
if(index==MAX)
{printf("The file is full\n");
return;
}
printf("Enter the persons name :");
scanf("%s",people[index+1].name);
printf("Enter the street number :");
scanf("%s",people[index+1].mail.streetnum);
printf("Enter the street name :");
scanf("%s",people[index+1].mail.street);
printf("Enter the apt number :");
scanf("%s",people[index+1].mail.apt);
printf("Enter the city :");
scanf("%s",people[index+1].mail.city);
printf("Enter the state :");
scanf("%s",people[index+1].mail.state);
printf("Enter the zip or postal code :");
scanf("%s",people[index+1].mail.zip);
printf("Enter the country :");
scanf("%s",people[index+1].mail.country);
printf("Enter the area code (three digits) :");
scanf("%d",&people[index+1].areacode);
printf("Enter the number :");
scanf("%d",&people[index+1].phone);

index++;
return;
}
void find(void)
{
int x;
char search[40];
printf("Enter the name you are looking for");
scanf("%s",search);
for(x=1;x<=index;x++)
{if(!strcmp(search,people[x].name))
{printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n",
people[x].name,
people[x].mail.streetnum,
people[x].mail.street,
people[x].mail.apt,
people[x].mail.city,
people[x].mail.state,
people[x].mail.zip,
people[x].mail.country,
people[x].areacode,
people[x].phone);
break;
}
}
return;
}
void save(void)
{int x=1;
datafile=fopen(pfile,"w");
fprintf(datafile,"%d ",index);
while(x<=index)
{fprintf(datafile,"%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n",
people[x].name,
people[x].mail.streetnum,
people[x].mail.street,
people[x].mail.apt,
people[x].mail.city,
people[x].mail.state,
people[x].mail.zip,
people[x].mail.country,
people[x].areacode,
people[x].phone);
x++;
}
fclose(datafile);
return;
}
void load(void)
{int x;
if(!(datafile=fopen(pfile,"r")))
{printf("The file doesn't exixt. It will be created upon saving\n");
index=0;
return;
}
fscanf(datafile,"%d",&index);
for(x=1;x<=index;x++)
{fprintf(datafile,"%s%s%s%s%s%s%s%s%d%d",
people[x].name,
people[x].mail.streetnum,
people[x].mail.street,
people[x].mail.apt,
people[x].mail.city,
people[x].mail.state,
people[x].mail.zip,
people[x].mail.country,
&people[x].areacode,
&people[x].phone);
}

fclose(datafile);

return;
}
void all(void)
{
int x=1;
while(x<=index)
{printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n",
people[x].name,
people[x].mail.streetnum,
people[x].mail.street,
people[x].mail.apt,
people[x].mail.city,
people[x].mail.state,
people[x].mail.zip,
people[x].mail.country,
people[x].areacode
, people[x].phone);
x++;
}
}
void change(void)
{printf("Enter the new filename");
scanf("%s",file);
load();
return;
}

There is a special datatype for use in structures called a 'bit field'. A
bit field can be of one or more bits. They are defined thus:

type name:size;

type is either int or unsigned. If it is signed the high order bit is
used to determine sign. They are accessed just like other members. The
book doesn't say whether they can be larger that one byte and all the
examples are less than one. Whether they are stored high-order to
low-order or visa-versa varies between compilers. They can be used with
other types of data in the same structure. They cannot be accessed with
pointers.

One thing I noticed that I must have missed earlier is that structures can
be saved as one piece of data instead of one element at a time as I have
been doing. I'll change this in the future.

The first exercise was to write a program that creates a structure with
three bit fields of lengths 3,3 and 2 assigns them values and displays the
values.

#include <stdio.h>
main(int argc, char *argv[], char *envp[])
{
struct bits
{
int a:3;
int b:3;
int c:2;
}bitfields;

bitfields.a=0;
bitfields.b=0;
bitfields.c=0;
do
{
printf("%d\t%d\t%d\n",bitfields.a,bitfields.b,bitfields.c);
bitfields.a++;
bitfields.b++;
bitfields.c++;
}
while((bitfields.a!=0)&&(bitfields.b!=0));
}

The second exercise was to find a function that reports the status of a
hardware device and write some programs that decode the status. I
couldn't find such a function.

A union is a way to overlap variables at the same address. They are
declared and addressed like structures except you use the keyword union.
Arrays are not compressed to have every element start at the same address.
The book doesn't say if they are aligned at the high-order byte or the
low-order byte. I'm assuming it is something that is compiler specific.
Instead of doing the exercise I did an experiment to determine whether
they are aligned at the high or low order byte in the EMX environment. Of
course this doesn't answer the question as to whether this is just the EMX
way of doing things or if it is a standard convention.

#include <stdio.h>
main(int argc, char *argv[], char *envp[])
{
union
{unsigned char ch;
unsigned short val;
unsigned int num;
}yoonyun;

yoonyun.num=0;
yoonyun.ch=0;
do
{printf("%u\t%u\t%u\n",
yoonyun.ch,yoonyun.val,yoonyun.num);
yoonyun.val++;
}
while(yoonyun.val);
}

From running this it appears that unions in EMX are aligned at the low
order byte. Since I have no idea how the various floating point values
are stored in the first place I can't say anything about them.


There are some type modifiers that affect how a variable is stored. To
use these modifiers precede the name with them:

modifier unsigned short int num;

The first is 'auto' and it is completily obsolete. It is a local variable.
It was included for backward compatibility with B, a language I've never
heard of.

'extern' is used for a variable that is used in a function in one file but
is declared in another file. The book doesn't address multiple file
programs. Appearantly that is something that really differs between
compilers. When I'm fisished with the book I'll figure that out. Anyway,
the 'extern' modifier is used when a variable is declared in files
subsequent to the first.

'register' tells the complier that the variable is to be stored in a manner
that allows the fastest access possible. This is usually done by placing
the variable in a CPU register but not necessarily so. Only so many
variable can be register variables. If more are declared that the allowed
the compiler will make some normal variables. The criteria for for which
is demoted is not specified. Because they may be placed in the CPU they
cannot be addressed by pointers.

'static' causes local variables to be preserved between calls to the
function that contains them. The variable is still only accessible by the
function. If it is applied to a global function it is only accessible by
functions declared in the same file in which it is declared. This enables
you to declare the same global variable in two different files.

The first exercise was to write a program that is called with an int and
reports how many times it has been called and by what values. Here it is:

#include <stdio.h>
#include <stdlib.h>
int recorder(int caller);

main(int argc, char *argv[], char *envp[])
{
while(recorder(rand())){};
}
int recorder(int caller)
{
static int index=0;
static int calls[20];
int x;
index++;
calls[index]=caller;
for(x=1;x<=index;x++) printf("%d\t%d\n",x,calls[x]);
if(index>=20)
return 0;
return 1;
}

One thing I'm wondering. Is it OK to have a loop with no statements
inside? I also noticed that rand() is a crappy random number generator.
It doesn't take a seed and on subsequent executions of the program it
generated the same sequence.

The next exercise was to compile one of the examples in the book which was
a multi file program to demonstrate the extern modifier. How to do it is
in the on-line docs.

Two additional modifiers are 'const' and volatile. 'const' prevents the
variable from being modified after declaration.

'volatile' tells the compiler that the variable may be changed by things
outside the program

The exercize was to write a program that uses a 'const' to embed a
version number of a program. Here it is:

#include <stdio.h>
main(int argc, char *argv[], char *envp[])
{
const float vernum=1.01;
printf("%f",vernum);
}

I wanted to see what would happen if I tried to change it in the program.
When I did the compiler reported an error.

The next exercize was to write a version of strcpy with the prototype

char *newstrcpy(char *to, const char *from);

that returns a pointer to to and demnostrate it in a program. Here it is:

#include <stdio.h>

char *newstrcpy(char *to, const char *from);

main(int argc, char *argv[], char *envp[])
{
char string1[80]="";
printf("%s\n",newstrcpy(string1,"string"));
printf("%s",string1);
}

char *newstrcpy(char *to, const char *from)
{int cp=0;
do
{
to[cp]=from[cp];
cp++;
}
while(from[cp]);
return to;
}

eda...@cts.com
Edmond Dantes


0 new messages