A NULL pointer changed after returned?

F

fix

Hi all,
I am new to C and I just started to program for a homework.
I included my code down there.
It is a fraction "class". I declared the Fraction struct, tried to
create some invalid fraction, with denominator zero.
A Fraction is created by the newFraction() function, and which in turns
call normalize() function to simplify it, but before, the normalize()
function will do a check, if the denominator is zero, it will give a
error by returning a NULL.
Everything works fine for a normal fraction, e.g. 3/4, 5/4, but if I
give a "4/0" to the function, it is frustrating.
In the normalize function, I am sure it is set to NULL, but back to
newFraction, it changed back to 4/0. But if I give a fraction that could
be simplified, such as 6/8, it is simpified and returned as 3/4 with
no problem.
Please help!
fix.

Fraction.c:
#include "Fraction.h"
void Case1c()
{
printFraction(newFraction(0,4));printf("\n");
printFraction(newFraction(4,0));printf("\n");
printFraction(newFraction(0,0));printf("\n");
}

int main(void)
{
printf("Case 1c:\n");Case1c();
return 0;
}

Fraction.h:
#include <stdio.h>

typedef struct {
int sign;
int numerator;
int denominator;
} Fraction;

int signOf(int number){
if (number < 0)
return -1;
else
return 1;
}

int gcd(int num1, int num2){
if (num1 < num2)
return gcd(num2, num1);
else
if ((num1 % num2) == 0)
return num2;
else
return gcd(num2, num1 % num2);
}

void normalize(Fraction *fr){
int factor;
if (fr->denominator == 0) // Invalid function
{
fr = NULL; // set it to NULL and return

printf("Set fr = NULL\n");
if (fr!=NULL)
printf("Not null");
else
printf("null");
return;
}
// Take the signs form the numerator and denominator to the sign variable
fr->sign *= signOf(fr->numerator);
fr->sign *= signOf(fr->denominator);

// Absolute the numerator and denominator
fr->numerator *= signOf(fr->numerator);
fr->denominator *= signOf(fr->denominator);

if (fr->numerator == 0)
{ // If the numerator is 0, simplify it to 0/1
fr->denominator = 1;
fr->sign = 1;
}
else
{ // Find the gcd of the numerator and denominator, divide them by the gcd
factor = gcd(fr->numerator, fr->denominator);
fr->numerator /= factor;
fr->denominator /= factor;
}
}


Fraction newFraction(int num, int den)
{
Fraction fr;
Fraction *frp;

fr.numerator = num;
fr.denominator = den;
fr.sign = 1;
frp = &fr;
normalize(frp);
if (frp!=NULL)
printf("Not null");
else
printf("null");

return fr;
}
void printFraction(Fraction fr)
{
if (&fr == NULL)
printf("Invalid fraction");

if (fr.sign == -1)
printf("-");
printf("%i/%i", fr.numerator, fr.denominator);
}
 
B

Ben Pfaff

fix said:
void normalize(Fraction *fr){
int factor;
if (fr->denominator == 0) // Invalid function
{
fr = NULL; // set it to NULL and return

printf("Set fr = NULL\n");
if (fr!=NULL)
printf("Not null");
else
printf("null");
return;

This is in the FAQ.

4.8: I have a function which accepts, and is supposed to initialize,
a pointer:

void f(int *ip)
{
static int dummy = 5;
ip = &dummy;
}

But when I call it like this:

int *ip;
f(ip);

the pointer in the caller remains unchanged.

A: Are you sure the function initialized what you thought it did?
Remember that arguments in C are passed by value. The called
function altered only the passed copy of the pointer. You'll
either want to pass the address of the pointer (the function
will end up accepting a pointer-to-a-pointer), or have the
function return the pointer.

See also questions 4.9 and 4.11.
 
D

Derk Gwen

# void normalize(Fraction *fr){

This copies the Fraction* parameter value into a local variable fr.
All changes to fr itself are to this local variable and not propagated
back to the caller. It's changes to *fr (or fr->...) that are visible
to the caller.

You can instead do something like
Fraction *normalize(Fraction *fr) {
...
return fr;
}
which propagates changes back to the caller as the function yield.
You can then call
frp = normalize(frp);
if (frp!=NULL)
printf("Not null");
else
printf("null");

# frp = &fr;
# normalize(frp);

This passes the address of the structure, not the address of pointer
variable to the structure.
 
E

Emmanuel Delahaye

In 'comp.lang.c' said:
Fraction.c:
#include "Fraction.h"
<snipped>

First of all, I highly recommend that you change your code organization. It's
a very bad idea to have code included in a .h. I suggest a very common
approach as follow:

/* main.c */
#include "Fraction.h"
#include <stdio.h>

/* macros ============================================================== */
/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */
/* private variables =================================================== */
/* private functions =================================================== */

static void Case1c (void)
{
printFraction (newFraction (0, 4));
printf ("\n");
printFraction (newFraction (4, 0));
printf ("\n");
printFraction (newFraction (0, 0));
printf ("\n");
}

/* entry point ========================================================= */

int main (void)
{
printf ("Case 1c:\n");
Case1c ();
return 0;
}

/* public variables ==================================================== */

/* fraction.h */
#ifndef H_FRACTION
#define H_FRACTION
/* macros ============================================================== */
/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */

typedef struct
{
int sign;
int numerator;
int denominator;
}
Fraction;

/* internal public functions =========================================== */
/* entry points ======================================================== */

Fraction newFraction (int num, int den);
void printFraction (Fraction fr);

/* public variables ==================================================== */

#endif /* guard */

/* fraction.c */
#include <stdio.h>
#include "fraction.h"

/* macros ============================================================== */
/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */
/* private variables =================================================== */
/* private functions =================================================== */

static int signOf (int number)
{
if (number < 0)
return -1;
else
return 1;
}

static int gcd (int num1, int num2)
{
if (num1 < num2)
return gcd (num2, num1);
else if ((num1 % num2) == 0)
return num2;
else
return gcd (num2, num1 % num2);
}

static void normalize (Fraction * fr)
{
int factor;
if (fr->denominator == 0) /* Invalid function */
{
fr = NULL; /* set it to NULL and return */

printf ("Set fr = NULL\n");
if (fr != NULL)
printf ("Not null");
else
printf ("null");
return;
}
/* Take the signs form the numerator and denominator to the sign variable
*/
fr->sign *= signOf (fr->numerator);
fr->sign *= signOf (fr->denominator);

/* Absolute the numerator and denominator */
fr->numerator *= signOf (fr->numerator);
fr->denominator *= signOf (fr->denominator);

if (fr->numerator == 0)
{ /* If the numerator is 0, simplify it to 0/1
*/
fr->denominator = 1;
fr->sign = 1;
}
else
{ /* Find the gcd of the numerator and
denominator, divide them by the gcd */
factor = gcd (fr->numerator, fr->denominator);
fr->numerator /= factor;
fr->denominator /= factor;
}
}

/* internal public functions =========================================== */
/* entry points ======================================================== */

Fraction newFraction (int num, int den)
{
Fraction fr;
Fraction *frp;

fr.numerator = num;
fr.denominator = den;
fr.sign = 1;
frp = &fr;
normalize (frp);
if (frp != NULL)
printf ("Not null");
else
printf ("null");

return fr;
}

void printFraction (Fraction fr)
{
if (&fr == NULL)
printf ("Invalid fraction");

if (fr.sign == -1)
printf ("-");
printf ("%i/%i", fr.numerator, fr.denominator);
}

/* public variables ==================================================== */

Note that I have no changed your code.
 
F

fix

Ben said:
This is in the FAQ.

4.8: I have a function which accepts, and is supposed to initialize,
a pointer:

void f(int *ip)
{
static int dummy = 5;
ip = &dummy;
}

But when I call it like this:

int *ip;
f(ip);

the pointer in the caller remains unchanged.

A: Are you sure the function initialized what you thought it did?
Remember that arguments in C are passed by value. The called
function altered only the passed copy of the pointer. You'll
either want to pass the address of the pointer (the function
will end up accepting a pointer-to-a-pointer), or have the
function return the pointer.

See also questions 4.9 and 4.11.

Ah...... I got you, so that means if I change the content in the struct,
i.e. changing the signs, denom and numerators, the pointer hasn't
changed, but if I point it to NULL, I am actually changing the pointer
so it reverts to the original value outside the function body.
If I am to return a pointer, I am curious that if I return a pointer to
a variable created inside the function, will the variable be garbage
collected but the pointer still pointing to that? I was learning Java
last semester and I have no trouble with pointers.......
 
F

fix

Derk said:
# void normalize(Fraction *fr){

This copies the Fraction* parameter value into a local variable fr.
All changes to fr itself are to this local variable and not propagated
back to the caller. It's changes to *fr (or fr->...) that are visible
to the caller.

You can instead do something like
Fraction *normalize(Fraction *fr) {
...
return fr;
}
which propagates changes back to the caller as the function yield.
You can then call
frp = normalize(frp);
if (frp!=NULL)
printf("Not null");
else
printf("null");

# frp = &fr;
# normalize(frp);

This passes the address of the structure, not the address of pointer
variable to the structure.


Yup thanks!
 
F

fix

Is this the order? Does C have any privacy (private
functions/variables)? And what is entry point?
Thanks.
/* macros ============================================================== */
/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */
/* private variables =================================================== */
/* private functions =================================================== */
/* entry point ========================================================= */
/* public variables ==================================================== */
 
E

Emmanuel Delahaye

In 'comp.lang.c' said:
Is this the order?

It's not /the/ order, it's mine, but actually, my experience has shown to me
that's it's hard to have another one!
Does C have any privacy (private
functions/variables)?

sure, by the use of the 'static' word.
/* macros ============================================================== */
/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */
/* private variables =================================================== */
/* private functions =================================================== */
/* entry point ========================================================= */
/* public variables ==================================================== */
And what is entry point?

This list was retrieved from a 'main.c' which is the source file that holds
the main() function. This function being by-definition the top-level function
of the application, it is also the unique entry point (the first entry) of
the module.
 
B

Ben Pfaff

fix said:
Ah...... I got you, so that means if I change the content in the
struct, i.e. changing the signs, denom and numerators, the pointer
hasn't changed, but if I point it to NULL, I am actually changing the
pointer so it reverts to the original value outside the function body.
If I am to return a pointer, I am curious that if I return a pointer
to a variable created inside the function, will the variable be
garbage collected but the pointer still pointing to that? I was
learning Java last semester and I have no trouble with pointers.......

C doesn't have garbage collection.

You really need to read the FAQ. This is also a FAQ.

7.5a: I have a function that is supposed to return a string, but when
it returns to its caller, the returned string is garbage.

A: Make sure that the pointed-to memory is properly allocated.
For example, make sure you have *not* done something like

char *itoa(int n)
{
char retbuf[20]; /* WRONG */
sprintf(retbuf, "%d", n);
return retbuf; /* WRONG */
}

One fix (which is imperfect, especially if the function in
question is called recursively, or if several of its return
values are needed simultaneously) would be to declare the return
buffer as

static char retbuf[20];

See also questions 7.5b, 12.21, and 20.1.

References: ISO Sec. 6.1.2.4.
 
M

Malcolm

fix said:
Is this the order? Does C have any privacy (private
functions/variables)? And what is entry point?
Thanks.
The main unit of organisation for C is the file.
Typically a file will contain either one complex function, or a list of
related functions.
For example, my BASIC interpreter has a single, very complex function,
basic(const char *script), which allows a BASIC script to be run.
Needless to say there are many sub-functions which that function calls, for
instance there is a function to calculate the value of an algebraic
expression, a function to print output, a function to execute a conditional
jump. However I don't want the user to call any of these functions directly,
so they are private to that file, or static. There is only one entry point,
the basic() function itself.
There are also private variables. For instnace the first thing I do is read
all the line numbers and store them in a global array for fast access.
Obviously I don't want anyone messing with that array either, so these
variables are also declared static, or local to that file.
 
F

fix

Ben said:
Ah...... I got you, so that means if I change the content in the
struct, i.e. changing the signs, denom and numerators, the pointer
hasn't changed, but if I point it to NULL, I am actually changing the
pointer so it reverts to the original value outside the function body.
If I am to return a pointer, I am curious that if I return a pointer
to a variable created inside the function, will the variable be
garbage collected but the pointer still pointing to that? I was
learning Java last semester and I have no trouble with pointers.......


C doesn't have garbage collection.

You really need to read the FAQ. This is also a FAQ.

7.5a: I have a function that is supposed to return a string, but when
it returns to its caller, the returned string is garbage.

A: Make sure that the pointed-to memory is properly allocated.
For example, make sure you have *not* done something like

char *itoa(int n)
{
char retbuf[20]; /* WRONG */
sprintf(retbuf, "%d", n);
return retbuf; /* WRONG */
}

One fix (which is imperfect, especially if the function in
question is called recursively, or if several of its return
values are needed simultaneously) would be to declare the return
buffer as

static char retbuf[20];

See also questions 7.5b, 12.21, and 20.1.

References: ISO Sec. 6.1.2.4.

Thanks, where can I get the FAQ?
 
F

fix

Emmanuel said:
It's not /the/ order, it's mine, but actually, my experience has shown to me
that's it's hard to have another one!




sure, by the use of the 'static' word.




This list was retrieved from a 'main.c' which is the source file that holds
the main() function. This function being by-definition the top-level function
of the application, it is also the unique entry point (the first entry) of
the module.

Aha..... thanks!
 
F

fix

Malcolm said:
The main unit of organisation for C is the file.
Typically a file will contain either one complex function, or a list of
related functions.
For example, my BASIC interpreter has a single, very complex function,
basic(const char *script), which allows a BASIC script to be run.
Needless to say there are many sub-functions which that function calls, for
instance there is a function to calculate the value of an algebraic
expression, a function to print output, a function to execute a conditional
jump. However I don't want the user to call any of these functions directly,
so they are private to that file, or static. There is only one entry point,
the basic() function itself.
There are also private variables. For instnace the first thing I do is read
all the line numbers and store them in a global array for fast access.
Obviously I don't want anyone messing with that array either, so these
variables are also declared static, or local to that file.

Got it! thanks.
 
B

Barry Schwarz

Ah...... I got you, so that means if I change the content in the struct,
i.e. changing the signs, denom and numerators, the pointer hasn't
changed, but if I point it to NULL, I am actually changing the pointer
so it reverts to the original value outside the function body.
If I am to return a pointer, I am curious that if I return a pointer to
a variable created inside the function, will the variable be garbage
collected but the pointer still pointing to that? I was learning Java
last semester and I have no trouble with pointers.......

Almost.

C passes arguments to functions by value. This means the function
receives a private copy of the argument. This private copy ceases to
exist when the function returns to its caller. Any change to the
argument made by the function is lost when the function returns
because the change was made only to the private copy which no longer
exists. The original variable in the calling function was never
changed and therefore never reverts.

If the argument is a pointer, then the function can dereference the
pointer and make "permanent" changes to the object pointed to that
will persist after the function returns.

There is no garbage collector in C. If you allocate memory in a
function, that memory remains allocated until explicitly freed. This
allocation is completely independent of function boundaries. (One
frequent problem encountered is not returning the pointer to such
memory which immediately creates a memory leak.)


<<Remove the del for email>>
 
B

Barry Schwarz

Is this the order? Does C have any privacy (private
functions/variables)? And what is entry point?
Thanks.
/* macros ============================================================== */
/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */
/* private variables =================================================== */
/* private functions =================================================== */
/* entry point ========================================================= */
/* public variables ==================================================== */

Functions declared static are visible only within the translation unit
in which they appear.

Static variables declared at file scope are visible to all functions
but again only those within the same translation unit. (Static has a
different meaning for variables declared inside a function.)

Entry point has multiple meanings.

In general, it means the definition of block of code which be the
target of a reference from a different translation unit. It is how
the linker resolves references to external functions. In C source
code, it is a function with the external attribute (the default if
static is not specified).

In the context of the post you were replying to, I think the
author intended something more specific and will let him comment.

The important point in that message which you seem to have glossed
over is that header files should not contain code or object
definitions. Header files should be restricted to typedef's,
prototypes, macros, and object/variable declarations. That is, they
should provide descriptions but not actually generate anything.


<<Remove the del for email>>
 

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,310
Messages
2,571,602
Members
48,419
Latest member
EstelaCout

Latest Threads

Top