if( mystruct == NULL )

mystruct is not a pointer, so you cannot compare it with NULL.

You have three options:

  1. Add a status field to MyStruct to indicate whether the struct has been initialized correctly.
  2. Allocate the struct on the heap and return it by pointer.
  3. Pass the structure as a pointer argument and return a status code (thanks @Potatoswatter).
Answer from NPE on Stack Overflow
🌐
Quora
quora.com › How-do-you-return-a-null-pointer-in-C
How to return a null pointer in C - Quora
Answer (1 of 7): “How do you return a null pointer in C?” This will do it: [code]return (void*)0; [/code]Enjoy your null pointer!
Discussions

pointers - When are you able to return NULL as the returning value of a C function? - Stack Overflow
I was wondering if you could tell me when you are able to return NULL, as the result of a function in C. For instance int lenght() can't return NULL because is is expecting an int in the return More on stackoverflow.com
🌐 stackoverflow.com
How to access the return value of a C function that can return null to return an error?
Hi, simple question here, I’m trying to find how to call a C function that can return null and catch the null case to return an error relative to the function’s meaning of null; uint8_t *string_bsearch(const uint8_t *s,… More on ziggit.dev
🌐 ziggit.dev
1
0
February 11, 2024
c - Unable to return NULL in a function that expects an integer return type - Stack Overflow
Warning: return makes integer from pointer without a cast [enabled by default] return NULL; I am trying to return NULL in my fucntion, but it's not working out and I don't understand why it is so. More on stackoverflow.com
🌐 stackoverflow.com
HELP:function at c returning (null)
i am rather new to c,and im trying to create a function that open a file,read a line,and return that line,but,on the part that open the file,it returns a warning,but if i take the same code and put directly into "int main()',it works,but then the function doesnt work,it returns null here is the... More on thecodingforums.com
🌐 thecodingforums.com
4
March 21, 2024
🌐
Reddit
reddit.com › r/c_programming › difference between return 1 and return null
r/C_Programming on Reddit: Difference between return 1 and return NULL
November 15, 2023 -

Source: https://cs50.harvard.edu/x/2023/labs/5/

Here is the portion that I need help with:

// Create a new individual with `generations`
person *create_family(int generations)
{
    // TODO: Allocate memory for new person
    person *new_person = malloc(sizeof(person));
    if (new_person == NULL)
    {
        return 1;
    }

Here is what ChatGPT says on my return 1 usage:

The TODO comment indicates that you need to allocate memory for a new person structure. In the provided code, you're using malloc(sizeof(person))to allocate memory dynamically. However, when memory allocation fails (i.e., malloc returns NULL), you're returning the integer 1 from the create_family function. Typically, a function returning a pointer should return NULL to indicate a failure.

Next, I rephrased the code:

// Create a new individual with `generations`
person *create_family(int generations)
{
    // TODO: Allocate memory for new person
    person *new_person = malloc(sizeof(person));
    if (!new_person)
    {
        return 1;
    }

ChatGPT reply:

Your updated code checks if new_person is NULL using the condition if (!new_person).

However, it's better to return NULL*(a pointer) in case of memory allocation failure, rather than the integer* 1.

Here's the modified code:

// Create a new individual with `generations`
person *create_family(int generations)
{
    // TODO: Allocate memory for new person
    person *new_person = malloc(sizeof(person));
    
    // Check if memory allocation was successful
    if (!new_person)
    {
        fprintf(stderr, "Memory allocation failed.\n");
        return NULL;
    }
    
    // Rest of the code for creating the family tree
    // ...

    return new_person;
}

In this modification:

  • If memory allocation fails, the function prints an error message to the standard error stream using fprintf(stderr, "Memory allocation failed.\n");

  • return NULL;
    is used to indicate that the function failed to create a new person due to a memory allocation failure.

  • If memory allocation is successful, the function proceeds with the rest of the code for creating the family tree.

Returning NULL in case of memory allocation failure is a common practice in C, as it allows the calling code to check for errors by examining the returned pointer.

Full project code provided by CS50:

// Simulate genetic inheritance of blood type

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// Each person has two parents and two alleles
typedef struct person
{
    struct person *parents[2];
    char alleles[2];
} person;

const int GENERATIONS = 3;
const int INDENT_LENGTH = 4;

person *create_family(int generations);
void print_family(person *p, int generation);
void free_family(person *p);
char random_allele();

int main(void)
{
    // Seed random number generator
    srand(time(0));

    // Create a new family with three generations
    person *p = create_family(GENERATIONS);

    // Print family tree of blood types
    print_family(p, 0);

    // Free memory
    free_family(p);
}

// Create a new individual with `generations`
person *create_family(int generations)
{
    // TODO: Allocate memory for new person
    person *new_person = malloc(sizeof(person));
    if (new_person == NULL)
    {
        return 1;
    }

    // If there are still generations left to create
    if (generations > 1)
    {
        // Create two new parents for current person by recursively calling create_family
        person *parent0 = create_family(generations - 1);
        person *parent1 = create_family(generations - 1);

        // TODO: Set parent pointers for current person

        // TODO: Randomly assign current person's alleles based on the alleles of their parents
    }

    // If there are no generations left to create
    else
    {
        // TODO: Set parent pointers to NULL

        // TODO: Randomly assign alleles
    }

    // TODO: Return newly created person
    return NULL;
}

// Free `p` and all ancestors of `p`.
void free_family(person *p)
{
    // TODO: Handle base case

    // TODO: Free parents recursively

    // TODO: Free child
}

// Print each family member and their alleles.
void print_family(person *p, int generation)
{
    // Handle base case
    if (p == NULL)
    {
        return;
    }

    // Print indentation
    for (int i = 0; i < generation * INDENT_LENGTH; i++)
    {
        printf(" ");
    }

    // Print person
    if (generation == 0)
    {
        printf("Child (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }
    else if (generation == 1)
    {
        printf("Parent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }
    else
    {
        for (int i = 0; i < generation - 2; i++)
        {
            printf("Great-");
        }
        printf("Grandparent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }

    // Print parents of current generation
    print_family(p->parents[0], generation + 1);
    print_family(p->parents[1], generation + 1);
}

// Randomly chooses a blood type allele.
char random_allele()
{
    int r = rand() % 3;
    if (r == 0)
    {
        return 'A';
    }
    else if (r == 1)
    {
        return 'B';
    }
    else
    {
        return 'O';
    }
}

🌐
W3Schools
w3schools.com › c › c_null.php
C NULL
You can compare a pointer to NULL to check if it is safe to use. Many C functions return NULL when something goes wrong. For example, fopen() returns NULL if a file cannot be opened, and malloc() returns NULL if memory allocation fails.
Top answer
1 of 5
5

NULL is a pointer value - or rather a null-pointer value.

NULL means that the function can't find where your pointer should point to - for example if you want to open a file, but it doesn't work your file pointer is returned as NULL. So you can test the value of a pointer and check to see if it worked or not.

If you are writing a routine

int length()

then you could return a negative value if length is unable to read the length of whatever you send it - this would be a way of indicating an error, because normally lengths can never be negative....

2 of 5
3

It is a matter of convention and you should clearly have one in your head and document it (at least in comments).

Sometimes a pointer really should always point to a valid address (see this intSwap example, both arguments should be valid pointers). At other times, it should either be such a valid address, or be NULL. Conceptually the pointer type is then by convention a sum type (between genuine pointer addresses and the special NULL value).

Notice that the C language does not have a type (or a notation) which enforces that some given pointer is always valid and non-null. BTW, with GCC specifically, you can annotate a function with __attribute__ using nonnull to express that a given argument is never null.

A typical example is FILE* pointers in <stdio.h>. The fopen function is documented to be able to return NULL (on failure), or some valid pointer. But the fprintf function is expecting a valid pointer (and passing NULL to it as the first argument is some undefined behavior, often a segmentation fault; and UB is really bad).

Some non-portable programs even use several "special" pointer values (which should not be dereferenced), e.g. (on Linux/x86-64) #define SPECIAL_SLOT (void*)((intptr_t)-1) (which we know that on Linux it is never a valid address). Then we could have the convention that a pointer is a valid pointer to a valid memory zone, or NULL or SPECIAL_SLOT (hence, if seen as an abstract data type, it is a sum type of two distinct invalid pointers NULL and SPECIAL_SLOT and the set of valid addresses). Another example is MAP_FAILURE as result of mmap(2) on Linux.

BTW, when using pointers in C to heap allocated data (indirectly obtained with malloc), you also need conventions about who is in charge of releasing the data (by using free, often thru a supplied function to free a data and all its internal stuff).

Good C programming requires many explicit conventions regarding pointers, and it is essential to understand them precisely and document them well. Look for example[s] into GTK. Read also about restrict.

🌐
Quora
quora.com › Is-it-legal-in-C-C-to-return-NULL
Is it legal in C/C++ to 'return NULL'? - Quora
Answer (1 of 21): There is no such thing like “C/C++”. return NULL is legal in C and it usually means, by convention, that something went wrong, e.g. an allocation, and the calling context is supposed to handle the error. In C++, while return nullptr would be legal and well-defined too, ...
🌐
Eskimo
eskimo.com › ~scs › cclass › notes › sx10d.html
10.4 Null Pointers
When we're done with the inner loop, if we reached the end of the pattern string (*p1 == '\0'), it means that all preceding characters matched, and we found a complete match for the pattern starting at start, so we return start. Otherwise, we go around the outer loop again, to try another starting position. If we run out of those (if *start == '\0'), without finding a match, we return a null pointer.
Find elsewhere
🌐
The Coding Forums
thecodingforums.com › programming languages › c, c++ and c#
HELP:function at c returning (null) | C, C++ and C# | Coding Forums
March 21, 2024 - #include <stdio.h> #include <stdlib.h> /* * todo can be -> * 1 -> read * 2 -> wright * 3 -> overwright * WILL ADD MORE */ /* * mode can be -> * 0 -> none of the below * 1 -> read all lines * 2 -> read one line * WILL ADD MORE */ char *open_readF(char *filepath,const int mode,const int todo){ FILE *file = fopen(filepath,"r"); char result[100]; fgets(result, 100, file); return result; } int main(){ /* here is the code that works,its the same,but it works somehow */ FILE *file = fopen("addons.c","r"); char result[100]; fgets(result, 100, file); printf("CODE STRIPED FROM FUNCTION ->%s\n",result); char *var = open_readF("addons.c",0,1); printf("FUNCTION ->%s\n",var); return 0; }
🌐
SEI CERT
wiki.sei.cmu.edu › confluence › display › c › MSC19-C.+For+functions+that+return+an+array,+prefer+returning+an+empty+array+over+a+null+value
MSC19-C. For functions that return an array, prefer returning an empty array over a null value - SEI CERT C Coding Standard - Confluence
Many functions have the option of returning a pointer to an object or returning NULL if a valid pointer cannot be produced. Some functions return arrays, which appear like a pointer to an object. However, if a function has the option of returning an array or indicating that a valid array is not possible, it should not return NULL.
Top answer
1 of 2
5

[H]ow do I return NULL from a integer result type function?

You don't. NULL is a macro representing a value of type void *. It is not an int, so a function returning int cannot return NULL.

Now, it is possible to convert NULL or any other pointer to type int, but the result of such a conversion is a valid, ordinary int. You seem to be looking instead for some kind of distinguished value, but there is none available unless you reserve such a value yourself. For example, you might reserve INT_MIN for that purpose. Of the built-in types, only pointer types afford general-purpose distinguished values (null pointers).

To provide for your function to signal failure to the caller, you have a couple of alternatives to reserving a value. The most common one is to use the function's return value only to report on the success or failure of the call, and to deliver any output -- in your case a node's value -- via a pointer argument:

int valueOf(t_node *node, int n, int *result) {
    int current = 0;

    while (current < n && node != NULL) {
        node = node->next;
        current += 1;
    }

    if (node == NULL) {
        // no such node -- return a failure code
        return 0;
    } else {
        // current == n
        *result = node->value;
        return 1;
    }
}
2 of 2
4

In C, NULL is just a synonym for 0. So you really only need to do this...

if (current > n) {
    return 0;
}

However, NULL usually refers to a pointer value that is undefined and not an integer. In C, integer values are not references as they are in many interpreted languages. They are scalar and can't be referred to implicitly with a pointer.

If you want to indicate an error condition or undefined behavior when current > n, you will have to provide a separate mechanism for indicating that the value isn't usable. Usually, C functions will return a -1 on an error. Since you are using the integer return for a value, that would mean that a valid value could never be -1.

It looks like you're handling a linked list and you want to limit the number of items to be checked. A possible way around this might be...

int valueOf(t_node *node, int n, int *val){
    int current = 0;
    int value;
    while (node -> next != NULL) {
        value = node -> val;
        if (current == n) {
            // This notation is for dereferencing a pointer.
            *val = value;
            return 0;
        }
        if (current > n) {
            return -1;
        }
        node = node -> next;
        current += 1;
    }
    // This method also gives you a way to indicate that
    // you came to the end of the list. Your code snippet
    // would have returned an undefined value if node->next == null
    return -1;
}
🌐
Reddit
reddit.com › r/c_programming › can you return null from a function that returns a multidimensional ***pointer?
r/C_Programming on Reddit: Can you return NULL from a function that returns a multidimensional ***pointer?
January 17, 2022 -

I am very sure that someone told me once that NULL is defined as a pointer to void. I leafed through the K&R, and NULL was just said to be interchangeable with zero.

But either way, if I have a function that returns a 3d char array (array of arrays of strings), can I then return NULL if something goes wrong? will it be a valid return type?

Many functions that return pointers return NULL if something goes wrong - fopen for instance where you check for NULL and then perror.

But I am confused about multi-dimensional pointers.

I mean, I know that they are technically just pointers. I am unsure what the multiple asterisks do except tell the programmer how many dimensions there are. Hmmm Is this the solution?

Comments?

🌐
Bytes
bytes.com › home › forum › topic
how can I return nothing? - Post.Byes
September 19, 2007 - " A C function either returns a value of a specified type, or never returns a value of any kind (such a function is written as if it "returned" a value of the type `void'). There are a few avenues open to you. One is to return either the prime number or some obvious non- prime like 0 or -1; ...
🌐
Unstop
unstop.com › home › blog › null pointer in c | a detailed explanation with examples
Null Pointer In C | A Detailed Explanation With Examples
May 3, 2024 - Memory Allocation Failures: Functions like malloc(), calloc(), and realloc() return NULL if they fail to allocate the requested memory. Initializing Pointers: Always initialize pointers to NULL when declaring them if you don't have a valid memory ...
Top answer
1 of 4
13

NULL is a pointer literal which is defined to contain a special value.

One possible definition is:

#define NULL ((void *)0)

For more detail you can read this faq

About const string& foo(), I believe you mean C++'s std::string. std::string has no implicit constructor that initialize it with NULL pointer. So you should use some exception or empty string to indicate an error to the caller. (If you are not throwing, you must return an std::string. Even if the object returned is local, its life is prolonged when kept in a local constant reference. But returning some other type and expecting an implicit conversion is not a good idea.)

Answer to your question: Because NULL is a literal, no temporary object may be created most of the time and actual value can be directly returned to the caller.

2 of 4
3

This function

const string& foo(); 

does not return a pointer. It returns a constant reference to an object of type std::string. So its return value may not be assigned to a pointer.

According to the C++ Standard

4.10 Pointer conversions [conv.ptr]

1 A null pointer constant is an integer literal (2.14.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a null pointer value. —end note ]

So when you use null pointer constant defined with macro NULL it is assigned to the return pointer of the function that will contain null pointer value of type node *

🌐
Reddit
reddit.com › r/c_programming › return null versus return
r/C_Programming on Reddit: return NULL versus return
November 19, 2023 -

While freeing memory, this is how I proceeded:

// Free `p` and all ancestors of `p`.
void free_family(person *p)
{
    // TODO: Handle base case
    if (p == NULL)
      {
        return NULL;
      }

It appears (ChatGPT) that the following will be the correct way:

// Free `p` and all ancestors of `p`.
void free_family(person *p)
{
    // Handle base case
    if (p == NULL)
    {
        return;
    }

In the context of freeing memory, you typically don't return anything (NULLor otherwise) because you are modifying memory, not producing a result (ChatGPT).

The distinction seems subtle and somewhat vague though makes sense.

Source: https://learning.edx.org/course/course-v1:HarvardX+CS50+X/home

Top answer
1 of 9
29

I think you need something like

Normal* Sphere::hit(Ray ray) {
   //stuff is done here
   if(something happens) {
       return NULL;
   }
   //other stuff
   return new Normal(something, somethingElse);
}

to be able to return NULL;

2 of 9
29

There are several fairly standard ways of doing this. There are different tradeoffs for the methods, which I'm not going to go into here.

Method 1: Throw an exception on failure.

Normal Sphere::hit(Ray ray)
{
   //stuff is done here
   if(something happens) {
       throw InvalidIntersection;
   }
   //other stuff
   return Normal(something, somethingElse);
}

void example(Ray r)
{
   try {
     Normal n = s.hit(r);
     ... SUCCESS CASE ...
   }
   catch( InvalidIntersection& )
   {
      ... FAILURE CASE ...
   }
}

Method 2 return a pointer to a newly allocated object. (You could also use smart pointers, or auto_ptrs to make this a little neater).

Normal* Sphere::hit(Ray ray)
{
   //stuff is done here
   if(something happens) {
       return NULL
   }
   //other stuff
   return new Normal(something, somethingElse);
}

void example(Ray ray)
{
  Normal * n = s.hit(ray);
  if(!n) {
     ... FAILURE CASE ...
  } else {
    ... SUCCESS CASE ...
    delete n;
  }
}

Method 3 is to update an existing object. (You could pass a reference, but a convention I use is that any output parameter is passed by pointer).

bool Sphere::hit(Ray ray, Normal* n)
{
   //stuff is done here
   if(something happens) {
       return false
   }
   //other stuff
   if(n) *n = Normal(something, somethingElse);
   return true;
}

void example(Ray ray)
{
  Normal n;
  if( s.hit(ray, &n) ) {
     ... SUCCESS CASE ...
  } else {
     ... FAILURE CASE ...
  }
}

Method 4: Return an optional<Normal> (using boost or similar)

optional<Normal> Sphere::hit(Ray ray)
{
   //stuff is done here
   if(something happens) {
       return optional<Normal>();
   }
   //other stuff
   return optional<Normal>(Normal(something, somethingElse));
}

void example(Ray ray)
{
  optional<Normal> n = s.hit(ray);
  if( n ) {
     ... SUCCESS CASE (use *n)...
  } else {
     ... FAILURE CASE ...
  }
}
Top answer
1 of 3
12

In C, NULL is a macro that expands either to 0 or (void*)0 (or something that has a similar effect).

In the first case, you can not differentiate between NULL and 0, because they are literally the same.
In the second case, your code will cause a compile error, because you can't compare an integer variable with a pointer.

2 of 3
4

First some background ...


The macros are NULL which expands to an implementation-defined null pointer constant; C11 §7.19 3

NULL typically is an integer constant 0 or (void*)0 or the like. It may have a different implementation or type - It could be ((int*) 0xDEADBEEF) as strange as that may be.

NULL might be type int. It might be type void * or something else. The type of NULL is not defined.


When the null pointer constant NULL is cast to any pointer, is is a null pointer. An integer 0 cast to a pointer is also a null pointer. A system could have many different (bit-wise) null pointers. They all compare equally to each other. They all compare unequally to any valid object/function. Recall this compare is done as pointers, not integers.

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function. C11 §6.3.2.3 3

int x;
if (&x == NULL) ... // this is false

So after all that chapter and verse how to distinguish NULL from 0?

If the macro NULL is defined as an int 0 - it is game over - there is no difference between 0 and NULL.

If NULL is not an int, then code can use _Generic() to differentiate NULL and 0. This does not help OP's "Any change made can only be made within the function itself." requirement as that function accepts an int augment.

If NULL is an int that has a different bit-pattern than 0, then a simple memcmp() can differentiate.

I suspect the whole reason for this exercise is to realize there is no portable method to distinguish NULL from 0.