Home > database >  Why do we need a pointer here
Why do we need a pointer here

Time:12-15

I'm new to C and while going through pointers I don't quite understand why do I need to use *p in the while loop condition check below.

It is a very simple function that counts occurences of the character x in the array with an example invocation as in the below main function. We assume here that p will point to an array of chars. Purely for demonstration. Thanks!


int count(char* p, char x) {

    int count = 0;
    while (*p != NULL) { // why *p requried here if p is already a pointer? 
        if (x == *p) count  ;
        p  ;
    }
    return count;

}

int main(){

    char a[5] = {'a','a','c','a',NULL};
    char* p = a; 
    std::cout << count(p, 'a') << std::endl; 
}

I.e why do I need

while (*p != NULL)

Since p is already a pointer I thought

while (p != NULL)

should be enough, but program crashes.

CodePudding user response:

Incrementing the pointer will make it point to the next element in the character array. Incrementing the pointer will never make it equal to a nullpointer or NULL.

c-strings are nul-terminated. The end of the string is marked with an element with value \0. In main this is the last element of the array and the loop in the function will stop when it reaches that last element.

p is the pointer to the element. *p is the element.

Using NULL for that condition is misleading. NULL should not be used in C anymore. A null pointer is nullptr and the terminator in strings is '\0'. The code works nevertheless because NULL just happens to equal 0 and '\0'. Tough, it was meant to be used for pointers, not for char.

The code can be written like this:

int count(char* p, char x) {

    int count = 0;
    while (*p != '\0') { // why *p requried here if p is already a pointer? 
        if (x == *p) count  ;
        p  ;
    }
    return count;

}

int main(){

    char a[5] = {'a','a','c','a','\0'};
    std::cout << count(a, 'a') << std::endl; 
}

Or better, use std::string and std::count:

#include <string>
#include <algorith>

int main() { 
     std::string s{"aaca"};
     std::cout << std::count(s.begin(),s.end(),'a'); 
}

Note that string literals automatically include the terminator. So "aaca" is a const char[5], an array of 5 characters, and the last one is '\0'. With std::string the details are a little hairy, but s[4] is also '\0'. Note that this is in contrast to other containers, where container[container.size()] is out-of-bounds and wrong.

CodePudding user response:

p is a pointer to char. So if you check the value of p it will be an address to that char (the first char in a string or array). So that address will be non-zero whether you are pointing to the first character or the last character.

In C or C strings are traditionally null terminated, meaning that the end of a string is marked by the null-terminator which is a single char with the value 0. To check the value of the char that the pointer p is pointing to, you need to de-reference it. De-referencing is done by prepending a * to the expression. In this case we extract the value that p is pointing to and not the address that p points to.

You are basically having an array of char, and as an example it might look like this in memory:

Address ASCII value Value
1000 97 (0x61) a
1001 97 (0x61) a
1002 99 (0x63) c
1003 97 (0x61) a
1004 0 (0x00) NULL

To begin with will point to the first char, that is address 1000, so the value of p is 1000, and the value of *p is 97 or 'a'. As you increment p it will change to 1001, 1002, etc. until it gets to 1004 where the value of p is 1004 and the value of *p will be 0.

Had you written while (p != NULL) instead of *p you would essentially have checked whether 1004 != 0 which would be true, and you would continue past the end of the string.

CodePudding user response:

I know a lot of (older) tutorials start with (naked) pointers and "C" style arrays but they are really not the first things you should use. If possible in C try to write solutions not depending in pointers. For holding text, use std::string.

#include <string>       // stop using char* for text
#include <algorithm>    // has the count_if method
#include <iostream>     

int count_matching_characters(const std::string& string, char character_to_match)
{
    int count{ 0 };

    // range based for loop, looping over al characters in the string
    for (const char c : string)
    {
        if (c == character_to_match) count  ;
    }
    return count;

    // or using a lambda function and algorithm
    /*
    return std::count_if(string.begin(), string.end(), [&](const char c)
    {
        return (character_to_match == c);
    });
    **/
}

int main()
{
    int count = count_matching_characters("hello world", 'l');
    std::cout << count;
    return 0;
}
  • Related