Help with a progam

B

Buck Rogers

Hi guys!

I am trying to do an excercise from my C book, which coincidently is very
similar to the one in the recent "program" thread.

Task: Write a program that uses redirection to accept input from a disk
file,
counts the number of times the first three letters of the alphabet (a, b,
c, and A, B, C)
occur in the file.

Below is my attempt:
==========================================
#include <stdio.h>
#include <stdlib.h>
#define MAX 1000 /*Maximum number of characters in the file */

int main( void)
{
char *ptr;
int count,
ctra = 0,
ctrb = 0,
ctrc = 0;

ptr = malloc(1000 * sizeof(char));
gets(ptr);
for (count = 0; count < MAX; count++) {
if( ptr[count] == 'a' || ptr[count] == 'A')
ctra++;
if( ptr[count] == 'b' || ptr[count] == 'B')
ctrb++;
if( ptr[count] == 'c' || ptr[count] == 'C')
ctrc++;
}
printf("ctra = %d\n", ctra);
printf("ctrb = %d\n", ctrb);
printf("ctrc = %d\n", ctrc);
free(ptr);
return 0;
}
==========================================
Problem: This works fine only if the maximum number of characters in
input.txt
is known(less than 1000).

I've tried including:

=======================
while ((ch = getchar()) != EOF) {
ctr++;
}
========================

The reason for this is so that I can use ctr in a malloc to
allocate enough memory to get all the characters in the file.

ie. ptr = malloc(ctr * sizeof(char));
gets(ptr);

However, because getchar *got* all the characters from stdin, the statement
gets(ptr) gets *nothing* from stdin.

I've been working on this for 2 days. It's driving me NUTTTSSSSS!!!
Can someone please give me a hint or 2?

Thanks in advance guys! Love your work!

Buck.
 
V

Vijay Kumar R Zanvar

[..]
#include <stdio.h>
#include <stdlib.h>

#include said:
#define MAX 1000 /*Maximum number of characters in the file */

int main( void)
{
char *ptr;
int count,
ctra = 0,
ctrb = 0,
ctrc = 0;

ptr = malloc(1000 * sizeof(char));

if ( !ptr )
{
perror ( "Malloc" );
exit ( EXIT_FAILURE );
}
gets(ptr);

gets() is dangerous. Use fgets(3), instead.
for (count = 0; count < MAX; count++) {
if( ptr[count] == 'a' || ptr[count] == 'A')
ctra++;
if( ptr[count] == 'b' || ptr[count] == 'B')
ctrb++;
if( ptr[count] == 'c' || ptr[count] == 'C')
ctrc++;
}

I would prefer this instead:

/* You said redirection? */
while ( fgets ( ptr, MAX, stdin ) )
{
char *a;

a = ptr;
while ( *a )
{
if ( toupper ( *a ) == 'A' )
ctra++;

if ( toupper ( *a ) == 'B' )
ctrb++;

if ( toupper ( *a ) == 'C' )
ctrc++;

a++;
}
}
printf("ctra = %d\n", ctra);
printf("ctrb = %d\n", ctrb);
printf("ctrc = %d\n", ctrc);
free(ptr);
return 0;
}
==========================================
Problem: This works fine only if the maximum number of characters in
input.txt
is known(less than 1000).

I guess this is because of gets ()!

[..]
 
A

Allan Bruce

Buck Rogers said:
Hi guys!

I am trying to do an excercise from my C book, which coincidently is very
similar to the one in the recent "program" thread.

Task: Write a program that uses redirection to accept input from a disk
file,
counts the number of times the first three letters of the alphabet (a, b,
c, and A, B, C)
occur in the file.

Below is my attempt:
==========================================
#include <stdio.h>
#include <stdlib.h>
#define MAX 1000 /*Maximum number of characters in the file */

int main( void)
{
char *ptr;
int count,
ctra = 0,
ctrb = 0,
ctrc = 0;

ptr = malloc(1000 * sizeof(char));
gets(ptr);
for (count = 0; count < MAX; count++) {
if( ptr[count] == 'a' || ptr[count] == 'A')
ctra++;
if( ptr[count] == 'b' || ptr[count] == 'B')
ctrb++;
if( ptr[count] == 'c' || ptr[count] == 'C')
ctrc++;
}
printf("ctra = %d\n", ctra);
printf("ctrb = %d\n", ctrb);
printf("ctrc = %d\n", ctrc);
free(ptr);
return 0;
}
==========================================
Problem: This works fine only if the maximum number of characters in
input.txt
is known(less than 1000).

I've tried including:

=======================
while ((ch = getchar()) != EOF) {
ctr++;
}
========================

The reason for this is so that I can use ctr in a malloc to
allocate enough memory to get all the characters in the file.

ie. ptr = malloc(ctr * sizeof(char));
gets(ptr);

However, because getchar *got* all the characters from stdin, the statement
gets(ptr) gets *nothing* from stdin.

I've been working on this for 2 days. It's driving me NUTTTSSSSS!!!
Can someone please give me a hint or 2?

Thanks in advance guys! Love your work!

Buck.

Here is some food for thought:

1) why dont you get each char, one at a time. This may not be fast, but it
will work.

2) If you want to load in a block at a time, use fread()

3) If you want to load the complete file in at once, then look at fseek()
and ftell() to get the file size. I believe that this is only reliably
portable for non-binary files, but I could be mistaken.

HTH
Allan
 
M

Martin Ambuhl

Buck said:
Hi guys!

I am trying to do an excercise from my C book, which coincidently is very
similar to the one in the recent "program" thread.

Task: Write a program that uses redirection to accept input from a disk
file,
counts the number of times the first three letters of the alphabet (a,
b, c, and A, B, C)
occur in the file.

Below is my attempt:
==========================================
#include <stdio.h>
#include <stdlib.h>
#define MAX 1000 /*Maximum number of characters in the file */

int main( void)
{
char *ptr;

You are better off just have an int here,
int c; /* OK, a better name could be chosen */
int count,
ctra = 0,
ctrb = 0,
ctrc = 0;

ptr = malloc(1000 * sizeof(char));
gets(ptr);

just go through the file:
while ((c = fgetc(stdin)) != EOF) {
switch (c) /* using toupper or tolower would reduce
the number of cases */
{
case 'a':
case 'A': ctra++;
break;
case 'b':
case 'B': ctrb++;
break;
case 'c':
case 'C': ctrc++;
break;
default: break;
}
for (count = 0; count < MAX; count++) {
if( ptr[count] == 'a' || ptr[count] == 'A')
ctra++;
if( ptr[count] == 'b' || ptr[count] == 'B')
ctrb++;
if( ptr[count] == 'c' || ptr[count] == 'C')
ctrc++;
}
printf("ctra = %d\n", ctra);
printf("ctrb = %d\n", ctrb);
printf("ctrc = %d\n", ctrc);
free(ptr);
return 0;
}
==========================================
Problem: This works fine only if the maximum number of characters in
input.txt
is known(less than 1000).

See above.
I've tried including:

=======================
while ((ch = getchar()) != EOF) {
ctr++;
}
========================

The reason for this is so that I can use ctr in a malloc to
allocate enough memory to get all the characters in the file.

ie. ptr = malloc(ctr * sizeof(char));
gets(ptr);

Even if you wanted all the characters in the file, using gets() is not the
way to do it. First, gets() is inherently evil. At least use fgets()
instead. But gets() will not get all the text in the file, but just the
first line. You would still need a loop. fread() is the the way to fill a
buffer, but is unnecessary for your exercise, since the input stream will
be buffered, anyway.
However, because getchar *got* all the characters from stdin, the statement
gets(ptr) gets *nothing* from stdin.

See above.
 
D

donLouis

Hi guys!

I am trying to do an excercise from my C book, which coincidently is very
similar to the one in the recent "program" thread.

Task: Write a program that uses redirection to accept input from a disk
file,
counts the number of times the first three letters of the alphabet (a, b,
c, and A, B, C)
occur in the file.

Below is my attempt:
==========================================
#include <stdio.h>
#include <stdlib.h>
#define MAX 1000 /*Maximum number of characters in the file */

int main( void)
{
char *ptr;
int count,
ctra = 0,
ctrb = 0,
ctrc = 0;

ptr = malloc(1000 * sizeof(char));
gets(ptr);
for (count = 0; count < MAX; count++) {
if( ptr[count] == 'a' || ptr[count] == 'A')
ctra++;
if( ptr[count] == 'b' || ptr[count] == 'B')
ctrb++;
if( ptr[count] == 'c' || ptr[count] == 'C')
ctrc++;
}
printf("ctra = %d\n", ctra);
printf("ctrb = %d\n", ctrb);
printf("ctrc = %d\n", ctrc);
free(ptr);
return 0;
}
==========================================
Problem: This works fine only if the maximum number of characters in
input.txt
is known(less than 1000).

I've tried including:

=======================
while ((ch = getchar()) != EOF) {
ctr++;
}
========================

The reason for this is so that I can use ctr in a malloc to
allocate enough memory to get all the characters in the file.

ie. ptr = malloc(ctr * sizeof(char));
gets(ptr);

However, because getchar *got* all the characters from stdin, the statement
gets(ptr) gets *nothing* from stdin.

Instead of setting an arbitrary limit to the number of characters,
or trying to figure out the exact number of characters before
processing them, consider this option; ignoring the number of
characters and just read until the end of file, i.e.:

while ((ch = getchar()) != EOF) {
/* if ch is A or a, increment ctra */
/* if ch is B or b, ... */ }

Note that although ch is getting chars for you to examine, it
is also going to get EOF as well, which is _not_ a char, but
an int, therefore ch should be declared as an int.
 
S

Sean Kenwrick

Buck Rogers said:
Hi guys!

I am trying to do an excercise from my C book, which coincidently is very
similar to the one in the recent "program" thread.

Task: Write a program that uses redirection to accept input from a disk
file,
counts the number of times the first three letters of the alphabet (a, b,
c, and A, B, C)
occur in the file.

Below is my attempt:
==========================================
#include <stdio.h>
#include <stdlib.h>
#define MAX 1000 /*Maximum number of characters in the file */

int main( void)
{
char *ptr;
int count,
ctra = 0,
ctrb = 0,
ctrc = 0;

ptr = malloc(1000 * sizeof(char));
gets(ptr);
for (count = 0; count < MAX; count++) {
if( ptr[count] == 'a' || ptr[count] == 'A')
ctra++;
if( ptr[count] == 'b' || ptr[count] == 'B')
ctrb++;
if( ptr[count] == 'c' || ptr[count] == 'C')
ctrc++;
}
printf("ctra = %d\n", ctra);
printf("ctrb = %d\n", ctrb);
printf("ctrc = %d\n", ctrc);
free(ptr);
return 0;
}
==========================================
Problem: This works fine only if the maximum number of characters in
input.txt
is known(less than 1000).

I've tried including:

=======================
while ((ch = getchar()) != EOF) {
ctr++;
}
========================

The reason for this is so that I can use ctr in a malloc to
allocate enough memory to get all the characters in the file.

ie. ptr = malloc(ctr * sizeof(char));
gets(ptr);

However, because getchar *got* all the characters from stdin, the statement
gets(ptr) gets *nothing* from stdin.

I've been working on this for 2 days. It's driving me NUTTTSSSSS!!!
Can someone please give me a hint or 2?

Thanks in advance guys! Love your work!

Buck.
If you insist on reading the file into memory first (rather than using
getchar() which is a better solution with stdin) then you can alway use
realloc() to increase the size of the memory buffer as required.

Also don't use gets() or fgets() since this will only read up to the first
newline character and thus you might loose alot of your data. Use fread()
instead - something like this...

#include <stdio.h>
#include <stdlib.h>
#define MAX 1000 /*Maximum number of characters to read each timee */

int main( void)
{
char *ptr;
int count,ctra = 0,ctrb = 0,ctrc = 0;
int bytes_read=MAX,i;

for(i=0;bytes_read==MAX;i++) {
if(i==0)
ptr = malloc(MAX * sizeof(char));
else
ptr=realloc(ptr,MAX*(i+1)*sizeof(char));

bytes_read=fread(ptr+MAX*i,1,MAX,stdin);
printf("bytes_read=%d\n",bytes_read);
for (count = 0; count < bytes_read; count++) {
if( ptr[count] == 'a' || ptr[count] == 'A')
ctra++;
if( ptr[count] == 'b' || ptr[count] == 'B')
ctrb++;
if( ptr[count] == 'c' || ptr[count] == 'C')
ctrc++;
}
}
printf("ctra = %d\n", ctra);
printf("ctrb = %d\n", ctrb);
printf("ctrc = %d\n", ctrc);
free(ptr);
return 0;
}
 
P

pete

Sean said:
{
if( ptr[count] == 'a' || ptr[count] == 'A')
ctra++;
if( ptr[count] == 'b' || ptr[count] == 'B')
ctrb++;
if( ptr[count] == 'c' || ptr[count] == 'C')
ctrc++;
}

A switch with the lower case cases falling through to the upper,
would be perfect there. As it is, when your code finds an 'a',
it keeps checking to see if the character, is also a 'b' and a 'c'.
 
S

Sean Kenwrick

pete said:
Sean said:
{
if( ptr[count] == 'a' || ptr[count] == 'A')
ctra++;
if( ptr[count] == 'b' || ptr[count] == 'B')
ctrb++;
if( ptr[count] == 'c' || ptr[count] == 'C')
ctrc++;
}

A switch with the lower case cases falling through to the upper,
would be perfect there. As it is, when your code finds an 'a',
it keeps checking to see if the character, is also a 'b' and a 'c'.
Yeh, this code was from the OPs program - I only changed the bits relating
to fread() and realloc().

I also forgot to add an offset to ptr after each realloc, something like
like this:

ch= (ptr+(1000)*(i+1))[count];

switch(ch){
case 'a':
case 'A':
...
}



Sean
 
J

Jack Klein

On Wed, 21 Jan 2004 15:58:38 +0530, "Vijay Kumar R Zanvar"

[snip]
gets() is dangerous. Use fgets(3), instead.

First sentence above, absolutely true. Second sentence above,
nonsense and undefined behavior.

C has a function with this prototype:

char *fgets(char *s, int n, FILE *stream);

....calling it with a single integer argument produces undefined
behavior.
 
J

Joona I Palaste

First sentence above, absolutely true. Second sentence above,
nonsense and undefined behavior.
C has a function with this prototype:
char *fgets(char *s, int n, FILE *stream);
...calling it with a single integer argument produces undefined
behavior.

I don't think Vijay meant the (3) as in an integer argument. He meant
the section of the man page it appears on. Yes, man pages are off-
topic here, but Vijay probably didn't know that.

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"And according to Occam's Toothbrush, we only need to optimise the most frequent
instructions."
- Teemu Kerola
 
V

Vijay Kumar R Zanvar

Joona I Palaste said:
I don't think Vijay meant the (3) as in an integer argument. He meant
the section of the man page it appears on. Yes, man pages are off-
topic here, but Vijay probably didn't know that.

True. This is what I meant, and also as a habit I wrote that way.

- Vijay
 
D

Dan Pop

In said:
On Wed, 21 Jan 2004 15:58:38 +0530, "Vijay Kumar R Zanvar"

[snip]
gets() is dangerous. Use fgets(3), instead.

First sentence above, absolutely true. Second sentence above,
nonsense and undefined behavior.

Neither nonsense, nor undefined behaviour, merely a common idiom among
Unix-literate people.
C has a function with this prototype:

char *fgets(char *s, int n, FILE *stream);

...calling it with a single integer argument produces undefined
behavior.

If a prototype declaration is in scope, there is no undefined behaviour:
calling fgets with a single integer argument *requires* a diagnostic.

But all this discussion is pointless, because the poster didn't write
fgets(3) inside a piece of C code, but inside a piece of English text.
Big difference!

Dan
 
O

Old Wolf

gets() is dangerous. Use fgets(3), instead.
C has a function with this prototype:

char *fgets(char *s, int n, FILE *stream);

...calling it with a single integer argument produces undefined
behavior.

It isn't required to be a compile error?
(assuming that the prototype is in scope)
 
D

Dave Thompson

(wants, actually unwisely, to alloc buffer for whole file)
Here is some food for thought:

1) why dont you get each char, one at a time. This may not be fast, but it
will work.

2) If you want to load in a block at a time, use fread()

3) If you want to load the complete file in at once, then look at fseek()
and ftell() to get the file size. I believe that this is only reliably
portable for non-binary files, but I could be mistaken.
It's not reliably portable at all, but it is somewhat *more* likely to
work for binary; ftell on text isn't even required to be a byte count.
FAQ 19.12.

An alternative, or fallback, is to malloc a buffer large enough for
"ordinary" or "typical" use, and realloc (geometrically rather than
linearly to keep the total cost from going quadratic) if (and
repeatedly while) needed.

- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top