From: yngvar@imr.no (Yngvar Foelling)
Subject: Re: largest structure size on pc (in c)
Organization: Institute of Marine Research, Bergen, Norway.
Date: Fri, 13 Nov 92 16:55:06 GMT

In article <92314.235722U17868@uicvm.uic.edu>, <U17868@uicvm.uic.edu> writes:
|> my  program is listed below. it is very short. All I am trying to do is to
|> read from a file. But, I think the problem is that the structure size is too bi
|> g. It compiles successfully.I am using Turbo C 2.0. When I run it I get the mes
|> sage "Null Pointer Assignment". I tried different ways that is using malloc, wi
|> thout malloc, defining structure as a tag and then declaring an instance, but n
|> othing helpded. I have 2M RAM on my pc.Anyone has any suggestion send it to
|> u17868@uicvm..cc.uic.edu
|> 

I'm a bit confused.  You say that you want to read from a file, but the code
seems to try to read from the keyboard and WRITE to the file.  Anyway, although
I can't say for certain what's causing the "Null pointer assignment" message,
there are enough mistakes in the program anyway, so let's walk through them:

|> #include <stdio.h>
|> #include <stdlib.h>
|> struct {
|> 	int  id;
|> 	char  date[9];
|> 	char day[10];
|> 	int  stime;
|> 	int  length;
|> 	char location[10];
|> 	char with_who[10];
|> 	char phone[11];
|> 	char subj[10];
|> 	char note[10];
|>         int  flag;
|> }temp;
|> 

Turbo C has a maximum size of 64K for a structure.  This structure is only 78
bytes long (a bit more if you turn on word alignment), so that is not the problem.

|> main()
|> {
|> int i;
|> FILE *file_pointer;
|>  file_pointer = fopen("activity.dat","rb+");

This is the only place where you hint at reading instead of writing.  You open
the file for reading AND writing, and this call fails if the file doesn't
exist.  It seems more sensible, given the following instructions, to use mode
"wb".

|>  fseek(file_pointer,0,0);

Completely redundant.  The file pointer is already positioned at the beginning
of the file.  But so long as it's there, it seems better to use SEEK_SET as the
third argument.  I'm not certain if the ANSI standard guarantees it to be set
to 0 or not, but it seems to be the "approved" form of the third argument.

|> 
|>  for(i=0;i<=4;i++)

Maybe I'm stating something obvious here, but this loop loops five times, and
not four.  If you really wanted four loops, write  for (i=0; i<4; i++)

|>      {
|>        scanf("%d",&temp.id);
|>        gets(temp.date);

This is the real big mistake in the program.  If you had inserted appropriate
printf/puts/fputs statements before each statement to prompt for the next
value, you would have discovered that gets takes its value from the same line
as the scanf call.  scanf skips all preceding whitespace, which includes any
newline you might hammer in with repeated banging of the RETURN key.  It then
tries to parse the next characters as an integer.  If it fails (the user made
a mistake), scanf returns but leaves the erroneous characters in the input
buffer to be read by gets.

But even if the user typed the value correctly, there's still a problem.  scanf
returns at the first character that can't be interpreted as an integer, but
again it leaves the remaining characters unread in the input buffer, which
includes the newline character.  gets will then read the remaining characters
on the line, instead of the next line as you probably intended.  It will do
this even if you hit RETURN directly after typing the number, in which case
gets will return with an empty string in temp.date.

This still leaves the problem that gets doesn't know the size of the string
temp.date, and happily overwrites any memory following it if the string is
longer than 8 characters.  I would say that this is the most likely cause of
the "Null pointer assignment" message.

|>        gets(temp.day);
|>        scanf("%d",&temp.stime);
|>        scanf("%d",&temp.length);
|>        gets(temp.location);
|>        gets(temp.with_who);
|>        gets(temp.phone);
|>        gets(temp.subj);
|>        gets(temp.note);
|>        scanf("%d",&temp.flag);

My notes above still apply.  I might add that if one scanf fails, and is
followed by a new scanf call, the second scanf will read the same characters
as the first, and so will also fail.

|>        fwrite(&temp,sizeof(temp),1,file_pointer);
|>        }
|>  }
|> 

You have no fclose(file_pointer).  That is not strictly necessary, though.

Conclusion: Don't use scanf or gets.  They both have big problems.  scanf has
no decent facilities for error recovery.  gets has no way of checking the size
of its argument.  Though more complicated, I'll suggest that you write wrapper
functions that read one single line and stores it in a variable, possibly after
some conversion, which could be done with sscanf, atoi or strtol.

-- 
Yngvar Flling (yngvar@imr.no)
Institute of Marine Research
Bergen
Norway
Newsgroups: comp.lang.c