Problem 77: Greedy Gift Givers

B

Bert

Problem is documented at http://ace.delos.com/usacoprob2?a=deAhyErCKsK&S=gift1

Why doesn't this work?

/*
ID: albert.4
LANG: C
TASK: gift1
*/

#include <stdio.h>

#define MAXNAMELEN 14

main()
{
struct friend {
int money, ngifts; /* no. gifts */

char name[MAXNAMELEN];
};

int NP; /* no. people */

FILE* in = fopen("gift1.in" , "r");
FILE* out = fopen("gift1.out", "w");

fscanf(in, "%d", &NP);

struct friend f[NP];

int i = 0;

for (; i < NP; i++)
{
fscanf(in, "%s", f.name);
}

/* Until input tells us how much each friend has (later in this
prog), they're all broke */
i = 0;

for (; i < NP; i++)
{
f.money = 0;
}

char temp[MAXNAMELEN];

for (i = 0; i < NP; i++)
{
fscanf(in, "%s", temp);

if (f.name == temp)
{
int init; /* initial amount of money */

fscanf(in, "%d %d", init, f.ngifts);

f.money = init * -1; /* init is given to people */
f.money += init % f.ngifts;

int amteachpersongets = init / f.ngifts;

int j = 0;

char temp2[MAXNAMELEN];

for (; j < f.ngifts; j++)
{
fscanf(in, "%s", temp2);

int k = 0;

for (; k < NP; k++)
{
if (f[k].name == temp2)
{
f[k].money += amteachpersongets;
break;
}
}
}
}
}

for (i = 0; i < NP; i++)
{
fprintf(out, "%s %d\n", f.name, f.money);
}

exit(0);
}
 
W

Walter Roberson

Why doesn't this work?

That line tells us that you are using a C89 compiler. A C99 compiler
would not have compiled that line because C99 does not the recognize
implicit int return type. Every C99 function must define -some- return
type, even if that return type is given as 'void' (which would
not be a good idea for the 'main' routine.)
int NP; /* no. people */
fscanf(in, "%d", &NP);
struct friend f[NP];

But those lines tell us that you are using C99. C89 array lengths
must be defined at compile time. C99 allows variable length arrays
(VLA) in some circumstances.

You need to pick a compiler standard and stick with it.
If you mix-and-match features between compiler versions, we
cannot tell you what the program means.
 
B

Bert

Bert said:
Problem is documented athttp://ace.delos.com/usacoprob2?a=deAhyErCKsK&S=gift1
Why doesn't this work?
main()
{

That line tells us that you are using a C89 compiler. A C99 compiler
would not have compiled that line because C99 does not the recognize
implicit int return type. Every C99 function must define -some- return
type, even if that return type is given as 'void' (which would
not be a good idea for the 'main' routine.)
int NP; /* no. people */
fscanf(in, "%d", &NP);
struct friend f[NP];

But those lines tell us that you are using C99. C89 array lengths
must be defined at compile time. C99 allows variable length arrays
(VLA) in some circumstances.

You need to pick a compiler standard and stick with it.
If you mix-and-match features between compiler versions, we
cannot tell you what the program means.

OK - I've been referring to K&R 2nd Edition.
main()
becomes int main()

Can you now tell me what's wrong with the rest of the program?
 
B

Ben Bacarisse

Bert said:
On Jul 6, 11:07 am, (e-mail address removed)-cnrc.gc.ca (Walter Roberson)

Best not to quote sig blocks.
OK - I've been referring to K&R 2nd Edition.
main()
becomes int main()

Can you now tell me what's wrong with the rest of the program?

The main things are (in no particular order):

(1) No error checking on things that can fail like fopen and fscanf.
(2) No decomposition into functions.
(3) Dangerous unbounded %s input formats.
(4) Misunderstanding how fscanf reads strings. Read FAQ 12.18a [1]
(4) Comparing strings by using == on pointers to them. FAQ 8.2.

[1] http://c-faq.com/
 
C

CBFalconer

Bert said:
Problem is documented at http://ace.delos.com/usacoprob2?a=deAhyErCKsK&S=gift1

Why doesn't this work?
.... snip ...

Because it doesn't compile under either C90 or C99.

[1] c:\c\junk>cc junk.c
junk.c: In function `main':
junk.c:17: warning: ISO C89 forbids variable-size array `f'
junk.c:17: warning: ISO C89 forbids mixed declarations and code
junk.c:31: warning: ISO C89 forbids mixed declarations and code
junk.c:37: warning: format argument is not a pointer (arg 3)
junk.c:37: warning: format argument is not a pointer (arg 4)
junk.c:42: warning: ISO C89 forbids mixed declarations and code
junk.c:49: warning: ISO C89 forbids mixed declarations and code
junk.c:64: warning: implicit declaration of function `exit'
junk.c:35: warning: `init' might be used uninitialized in this
function

[1] c:\c\junk>gcc -std=c99 -pedantic -W -Wall -Wwrite-strings
junk.c
junk.c: In function `main':
junk.c:37: warning: format argument is not a pointer (arg 3)
junk.c:37: warning: format argument is not a pointer (arg 4)
junk.c:64: warning: implicit declaration of function `exit'

This is line 37 as I have compressed it:
fscanf(in, "%d %d", init, f.ngifts);
 
B

Bert

Why doesn't it do the problem correctly now?

/*
ID: albert.4
LANG: C
TASK: gift1
*/

#include <stdio.h>

#define MAXNAMELEN 14

main()
{
struct friend {
int money, ngifts; /* no. gifts */

char name[MAXNAMELEN];
};

int NP; /* no. people */

FILE* in = fopen("gift1.in" , "r");
FILE* out = fopen("gift1.out", "w");

fscanf(in, "%d", &NP);

struct friend f[NP];

int i = 0;

for (; i < NP; i++)
{
fscanf(in, "%s", f.name);
}

/* Until input tells us how much each friend has (later in this
prog), they're all broke */
i = 0;

for (; i < NP; i++)
{
f.money = 0;
}

char temp[MAXNAMELEN];

for (i = 0; i < NP; i++)
{
fscanf(in, "%s", temp);

if (strcmp(f.name, temp) == 0)
{
int init; /* initial amount of money */

fscanf(in, "%d %d", &init, &f.ngifts);

f.money = init * -1; /* init is given to people */

if (f.ngifts != 0)
{
f.money += init % f.ngifts;
}

int amteachpersongets = 0;

if (f.ngifts != 0)
{
int amteachpersongets = init / f.ngifts;
}

int j = 0;

char temp2[MAXNAMELEN];

for (; j < f.ngifts; j++)
{
fscanf(in, "%s", temp2);

int k = 0;

for (; k < NP; k++)
{
if (strcmp(f[k].name, temp2) == 0)
{
f[k].money += amteachpersongets;
break;
}
}
}
}
}

for (i = 0; i < NP; i++)
{
fprintf(out, "%s %d\n", f.name, f.money);
}

exit(0);
}
 
B

Barry Schwarz

Problem is documented at http://ace.delos.com/usacoprob2?a=deAhyErCKsK&S=gift1

Why doesn't this work?

Would you care to describe "doesn't work" so we have a fighting chance
to help.
/*
ID: albert.4
LANG: C
TASK: gift1
*/

#include <stdio.h>

#define MAXNAMELEN 14

main()
{
struct friend {
int money, ngifts; /* no. gifts */

char name[MAXNAMELEN];
};

int NP; /* no. people */

FILE* in = fopen("gift1.in" , "r");
FILE* out = fopen("gift1.out", "w");

fscanf(in, "%d", &NP);

struct friend f[NP];

So your compiler has extensions that allow variable length arrays and
definitions to follow executable statements. Many of us don't which
limits the number of people who can help you.
int i = 0;

for (; i < NP; i++)
{
fscanf(in, "%s", f.name);


If you gave us a sample of your input it would also help.
}

/* Until input tells us how much each friend has (later in this
prog), they're all broke */
i = 0;

for (; i < NP; i++)
{
f.money = 0;


Is there some reason you chose not to do this in the previous loop?
}

char temp[MAXNAMELEN];

for (i = 0; i < NP; i++)
{
fscanf(in, "%s", temp);

Don't you think this should be in front of the loop?
if (f.name == temp)


This is guaranteed to always be false. If you want to compare
strings, you need to use strcmp et al. Read the faq (www.c-faq.com),
section 8.2. Then read the rest of the faq also.
{
int init; /* initial amount of money */

fscanf(in, "%d %d", init, f.ngifts);

f.money = init * -1; /* init is given to people */


Is there some reason -init does not provide the value you want?
f.money += init % f.ngifts;


What is this quantity supposed to represent?
int amteachpersongets = init / f.ngifts;

int j = 0;

char temp2[MAXNAMELEN];

for (; j < f.ngifts; j++)
{
fscanf(in, "%s", temp2);

int k = 0;

for (; k < NP; k++)
{
if (f[k].name == temp2)
{
f[k].money += amteachpersongets;
break;
}
}
}
}
}

for (i = 0; i < NP; i++)
{
fprintf(out, "%s %d\n", f.name, f.money);
}

exit(0);
}



Remove del for email
 
C

CBFalconer

Barry said:
Bert said:
Why doesn't this work?

Would you care to describe "doesn't work" so we have a fighting chance
to help.
..... snip ...
#include <stdio.h>

#define MAXNAMELEN 14

main()
{
struct friend {
int money, ngifts; /* no. gifts */
char name[MAXNAMELEN];
};

int NP; /* no. people */

FILE* in = fopen("gift1.in" , "r");
FILE* out = fopen("gift1.out", "w");

fscanf(in, "%d", &NP);
struct friend f[NP];

So your compiler has extensions that allow variable length arrays and
definitions to follow executable statements. Many of us don't which
limits the number of people who can help you.

Not to mention the use of undefined functions (exit) and implicit
int (main).
 
W

Willem

Richard Heathfield wrote:
) ITYM "undeclared functions". Either the presence of a standard C library
) function in the library supplied with the implementation counts as a
) definition or it doesn't. If it does, then exit() is defined. And if it
) doesn't, the mere addition of a declaration (via #include <stdlib.h>) will
) not provide a definition.

Is exit() required to be a library function by the standard ?
Can't it be a macro ? For example:

#define exit(x) _exitprocess((x) == EXIT_SUCCESS ? 1 : 0)

(On systems where a process returns 0 to the shell for failure).


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
S

santosh

Willem said:
Richard Heathfield wrote:
) ITYM "undeclared functions". Either the presence of a standard C
library ) function in the library supplied with the implementation
counts as a ) definition or it doesn't. If it does, then exit() is
defined. And if it ) doesn't, the mere addition of a declaration (via
#include <stdlib.h>) will ) not provide a definition.

Is exit() required to be a library function by the standard ?
Can't it be a macro ? For example:

#define exit(x) _exitprocess((x) == EXIT_SUCCESS ? 1 : 0)

(On systems where a process returns 0 to the shell for failure).

As far as I can see, exit could be implemented as a macro too, though a
function must also be provided.
 
C

CBFalconer

santosh said:
Willem wrote:
.... snip ...


As far as I can see, exit could be implemented as a macro too,
though a function must also be provided.

If it is a macro, that macro is defined by #include <stdlib.h>.
However, since it is a non-returning function, it appears awkward
to provide a macro for it.
 
K

Keith Thompson

Willem said:
Richard Heathfield wrote:
) ITYM "undeclared functions". Either the presence of a standard C library
) function in the library supplied with the implementation counts as a
) definition or it doesn't. If it does, then exit() is defined. And if it
) doesn't, the mere addition of a declaration (via #include <stdlib.h>) will
) not provide a definition.

Is exit() required to be a library function by the standard ?
Can't it be a macro ? For example:
[...]

Like any other library function, it must be provided as a function.
The implementation may optionally implement it as a macro as well.

In particular, assuming you have a "#include <stdlib.h>", this:

(exit)(0);

or this:

#undef exit
exit(0);

must bypass any macro definition and call the actual function.
Similarly, you can assign the address of the exit function to a
pointer object.
 
K

Keith Thompson

CBFalconer said:
If it is a macro, that macro is defined by #include <stdlib.h>.
However, since it is a non-returning function, it appears awkward
to provide a macro for it.

I see nothing awkward about it. Willem even provided a plausible
example.

Except that I'd put parentheses around the whole definition:

#define exit(x) (_exitprocess((x) == EXIT_SUCCESS ? 1 : 0))

It's easier to add the parentheses than to figure out whether they're
really necessary.
 
P

Peter Nilsson

Keith said:
...
Like any other library function, it must be provided as a function.

Well... it's unspecified whether setjmp is an identifier declared
with external linkage, which gives it scope to be a library function
that needn't be provided as a function! :)
 
C

CBFalconer

Keith said:
I see nothing awkward about it. Willem even provided a plausible
example.

Since the operation has to go somewhere and do something, it has to
transfer control. There must be code to which to transfer control
to. Since the code must exist and must be used, any macro is a
useless exercize. At least as I see it.
 
K

Keith Thompson

CBFalconer said:
Since the operation has to go somewhere and do something, it has to
transfer control. There must be code to which to transfer control
to. Since the code must exist and must be used, any macro is a
useless exercize. At least as I see it.

Read Willem's example again. The transfer of control is performed by
the _exitprocess() function. The macro serves to perform a simple
transformation on the argument.
 
K

Keith Thompson

Peter Nilsson said:
Well... it's unspecified whether setjmp is an identifier declared
with external linkage, which gives it scope to be a library function
that needn't be provided as a function! :)

Well, the standard refers to it as "the setjmp macro", even though it
apparently doesn't require it to be a macro.

In any case, setjmp would simply be the exception that proves the
rule, if exceptions proved rules, which of course they don't, so I
was, er, um, wrong.
 
B

Bert

Sorry adults

Greedy Gift Givers

A group of NP (2 ˜ NP ˜ 10) uniquely named friends has decided to
exchange gifts of money. Each of these friends might or might not give
some money to any or all of the other friends. Likewise, each friend
might or might not receive money from any or all of the other friends.
Your goal in this problem is to deduce how much more money each person
gives than they receive.

The rules for gift-giving are potentially different than you might
expect. Each person sets aside a certain amount of money to give and
divides this money evenly among all those to whom he or she is giving
a gift. No fractional money is available, so dividing 3 among 2
friends would be 1 each for the friends with 1 left over -- that 1
left over stays in the giver's "account".

In any group of friends, some people are more giving than others (or
at least may have more acquaintances) and some people have more money
than others.

Given a group of friends, no one of whom has a name longer than 14
characters, the money each person in the group spends on gifts, and a
(sub)list of friends to whom each person gives gifts, determine how
much more (or less) each person in the group gives than they receive.
IMPORTANT NOTE

The grader machine is a Linux machine that uses standard Unix
conventions: end of line is a single character often known as '\n'.
This differs from Windows, which ends lines with two charcters, '\n'
and '\r'. Do not let your program get trapped by this!
PROGRAM NAME: gift1
INPUT FORMAT
Line 1: The single integer, NP
Lines 2..NP+1: Each line contains the name of a group member
Lines NP+2..end: NP groups of lines organized like this:
The first line in the group tells the person's name who will be giving
gifts.
The second line in the group contains two numbers: The initial amount
of money (in the range 0..2000) to be divided up into gifts by the
giver and then the number of people to whom the giver will give gifts,
NGi (0 ˜ NGi ˜ NP-1).
If NGi is nonzero, each of the next NGi lines lists the the name of a
recipient of a gift.

SAMPLE INPUT (file gift1.in)

5
dave
laura
owen
vick
amr
dave
200 3
laura
owen
vick
owen
500 1
dave
amr
150 2
vick
owen
laura
0 2
amr
vick
vick
0 0

OUTPUT FORMAT

The output is NP lines, each with the name of a person followed by a
single blank followed by the net gain or loss (final_money_value -
initial_money_value) for that person. The names should be printed in
the same order they appear on line 2 of the input.

All gifts are integers. Each person gives the same integer amount of
money to each friend to whom any money is given, and gives as much as
possible that meets this constraint. Any money not given is kept by
the giver.
SAMPLE OUTPUT (file gift1.out)

dave 302
laura 66
owen -359
vick 141
amr -150


Submission file Name:
USACO Gateway | Comment or Question
 
W

Willem

Bert wrote:
) Why doesn't it do the problem correctly now?

What is the incorrect output then, and what should the correct output be ?


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 

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
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top