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....
Answer from tom on Stack Overflowpointers - When are you able to return NULL as the returning value of a C function? - Stack Overflow
c++ - returning NULL pointer in C - Stack Overflow
string - Returning NULL value from a function to a pointer in C - Stack Overflow
Can you return NULL from a function that returns a multidimensional ***pointer?
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....
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.
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.
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 *
There are few bugs in your code. Corrections would be
for(i = 0; sentence[i] && wordCount < words; i++)
Another is
while (inputString[i] !=' ' && inputString[i]!='\0')
And the last
if (words > wordCount)
Explanation for first one would be - you wont check past the end of the string. Otherwise you had undefined behavior.
There maybe cases when you reach the end of the string but still won't get a space. To avoid that case you need to consider the \0 case too.
If the words > wordCount then only you should throw the error. If they are equal then it should print the value.
This loop in skipWords is the problem. It'll traverse through the string and beyond because you're not checking for the end of the string.
for(i = 0; wordCount < words; i++)
{
if(sentence[i] == ' ')
{
wordCount++;
}
}
Since the only way out of the loop is for it to find as many spaces as you've passed in as words, it will always return NULL.
Arguably wordCount should also start at 1 since if there are no spaces in the string, you'll always have at least one word...unless the string is empty.
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?
Value of return type std::vector<int> cannot be nullptr.
The most straightforward way in this case is to return std::unique_ptr<std::vector<int>> instead - in this case it's possible to return nullptr.
Other options:
- throw an exception in case of fail
- use
optional<std::vector<int>>as return type (eitherboost::optionalorstd::optionalif your compiler has this C++17 feature) - return
boolparameter and havestd::vector<int>&as output parameter of function
The best way to go really depends on the use case. For example, if result vector of size 0 is equivalent to 'fail' - feel free to use this kind of knowledge in your code and just check if return vector is empty to know whether function failed or succeed.
In my practice I almost always stick to return optional (boost or std, depending on environment restriction).
Such interface is the most clear way to state the fact that 'result can either be present or not'.
To sum up - this is not a problem with the only one right solution. Possible options are listed above - and it's only a matter of your personal experience and environmental restrictions/convetions - which option to choose.
You could return a std::unique_ptr<std::vector<int>> and check that value, or throw an exception, or check vector.size() == 0 etc.