Checking for null before pointer usage

后端 未结 13 2571
孤独总比滥情好
孤独总比滥情好 2021-02-20 09:32

Most people use pointers like this...

if ( p != NULL ) {
  DoWhateverWithP();
}

However, if the pointer is null for whatever reason, the functi

相关标签:
13条回答
  • 2021-02-20 10:00

    I think it is better to check for null. Although, you can cut down on the amount of checks you need to make.

    For most cases I prefer a simple guard clause at the top of a function:

    if (p == NULL) return;
    

    That said, I typically only put the check on functions that are publicly exposed.

    However, when the null pointer in unexpected I will throw an exception. (There are some functions it doesn't make any sense to call with null, and the consumer should be responsible enough to use it right.)

    Constructor initialization can be used as an alternative to checking for null all the time. This is especially useful when the class contains a collection. The collection can be used throughout the class without checking whether it has been initialized.

    0 讨论(0)
  • 2021-02-20 10:02

    In addition to the other answers, it depends upon what NULL signifies. For example, this code is perfectly OK, and is pretty idiomatic:

    while (fgets(buf, sizeof buf, fp) != NULL) {
        process(buf);
    }
    

    Here, NULL value indicates not only error, but end-of-file condition as well. Similarly, strtok() returns NULL to say, "there are no more tokens" (although one should avoid strtok() to begin with, but I digress). In cases like this, it is perfectly OK to call a function if the returned pointer is not NULL, and do nothing otherwise.

    Edit: another example, closer to what was asked:

    const char *data = "this;is;a;test;";
    const char *curr = data;
    const char *p;
    while ((p = strchr(curr, ';')) != NULL) {
        /* process data in [curr, p) */
        process(curr, p);
        curr = p + 1;
    }
    

    Once again, NULL here is an indication from strchr() that it couldn't find a ;, and that we should stop processing the data further.

    Having said that, if NULL is not used as an indication, then it depends:

    • If the pointer can't be NULL at this point in code, it's useful to have an assert(p != NULL); when developing, and also having a fprintf(stderr, "Can't happen\n"); or equivalent statement, and then take whatever action as appropriate (abort() or similar is probably the only sane choice at this point).
    • If the pointer can be NULL, and it's not critical, it might be better to just bypass the usage of the null pointer. Suppose you're trying to allocate memory for writing a log message, and malloc() fails. You shouldn't abort the program because of this. If malloc() succeeds, you want to call a function (sprintf()/whatever) to fill the buffer.
    • If the pointer can be NULL, and it's critical. In this case, you probably want to fail, and hopefully such conditions don't happen too often.

    Secondly, consider you have a function that takes a pointer as an argument, and you use this function multiple times on multiple pointers throughout your program. Do you find it more beneficial to test for NULL in the function (the benefit being you don't have to test for NULL all over the place), or on the pointer before calling the function (the benefit being no overhead from calling the function)?

    This depends upon a lot of factors. If I can be sure sometimes or most of the times that the pointer passed to a function cannot be NULL, the extra check in the function is wasteful. If the pointer passed comes out of a lot of places, and it's tricky to put in a check everywhere, sure, then the check is good to have in the function itself.

    The standard library functions, for the most part, don't check for NULL: str*, mem* functions for example. An exception is free(), it does check for NULL.

    A comment about assert: assert is a no-op if NDEBUG is defined, so one should not use it for debugging—its only use is during development to catch programming errors. Also, in C89, assert takes an int, so assert(p != NULL) is better in such cases than a just plain assert(p).

    0 讨论(0)
  • 2021-02-20 10:03

    You are right in thinking that NULL pointers often result in immediate crashes, but do not forget that if you are indexing into a large array through a NULL pointer, you might indeed get a valid memory address if your index is high enough. And then, you'll get memory corruption or incorrect memory reads, which will be much harder to locate.

    Whenever I can assume that calling a function with NULL is a bug, which should never happen in production code, I prefer using ASSERT guards in the function, which are only compiled into real code in a debug build, and not checking for NULL otherwise.

    And from my point of view, generally, a function should check its arguments, not the caller. You should always assume that your callers might have been a bit sloppy about the checking, or that they might contain bugs...

    Morality: check for NULL in the function being called, either through some if() statement that throws, or using some ASSERT construct (possibly with a clear message of why this happened). Also check for NULL in the callers, but only if the callers know that this condition might happen in a normal program execution, and act accordingly.

    0 讨论(0)
  • 2021-02-20 10:03

    Dereferencing a null pointer is undefined behavior. If you want to crash if the pointer is null, use an assert or something similar (and, depending on the defined behavior of your class, that can be a perfectly valid response - it's certainly better than continuing to run when people may be expecting something to have been done!).

    Since the behavior of dereferencing a null pointer is undefined, it can do anything. Crash, corrupt memory, create a wormhole to an alternate dimension allowing the Elder Gods to come forth and devour all of mankind... anything. While bugs happen, depending upon undefined behavior is, by definition, a bug. So don't do it deliberately.

    0 讨论(0)
  • 2021-02-20 10:07

    This non-NULLness check can be avoided by using references instead of pointers. This way, the compiler ensures the parameter passed is not NULL. For example:

    void f(Param& param)
    {
        // "param" is a pointer that is guaranteed not to be NULL      
    }
    

    In this case, it is up to the client to do the checking. However, mostly the client situation will be like this:

    Param instance;
    f(instance);
    

    No non-NULLness checking is needed.

    When using with objects allocated on the heap, you can do the following:

    Param& instance = *new Param();
    f(*instance);
    

    Update: As user Crashworks remarks, it is still possible to make you program crash. However, when using references, it is the responsibility of the client to pass a valid reference, and as I show in the example, this is very easy to do.

    0 讨论(0)
  • 2021-02-20 10:08

    I think I've seen more of. This way you don't proceed if you know it's going to blow up anyway.

    if (NULL == p)
    {
      goto FunctionExit; // or some other common label to exit the function.
    }
    
    0 讨论(0)
提交回复
热议问题