Understanding Pointers to Function

Hello folks,
I am following some program so I could understand the logic behind pointers to functions; I am attaching the code. I do not understand the way they have declared a function with pointers? The function points to a character and it receives two arguments which point to two characters. instead of using “char* subStr (char* str, char delim, int index)" why cant we just use "char subStr (char str, char *delim, int index)” ? what difference does the Asterik make between two? Thank you for your help :slight_smile:

char* subStr (char* str, char *delim, int index) {
char *act, *sub, *ptr;
static char copy[MAX_STRING_LEN];
int i;

// Since strtok consumes the first arg, make a copy
strcpy(copy, str);

for (i = 1, act = copy; i <= index; i++, act = NULL) {
//Serial.print(".");
sub = strtok_r(act, delim, &ptr);
if (sub == NULL) break;
}
return sub;

}

In function arguments/parameters, an asterisk and square brackets are interchangeable. In declarations, the two are different. In declarations an asterisk declares a pointer to a variable, while brackets declare an array.

The code you posted is a function that returns a pointer. There is nothing in that snippet that deals with pointers to functions.

The function that you posted returns a string - a NULL terminated array of chars. How would you return that using just a single char variable?

Thank You for your reply. The entire function is bellow: it basically cuts some part of a given string and displays it. As I said i am following the logic. If sub is a pointer inside the function then why would we need to have the function pointed to some char instead of just returning *sub ?
// strtok test */

#include <string.h>

#define MAX_STRING_LEN 20

char *record1 = “one two three”;
char *record2 = “Hello there friend”;
char *p, *i;

void setup() {

Serial.begin(9600);

Serial.println("Split record1: ");
Serial.println(subStr(record1, " ", 1));
Serial.println(subStr(record1, " ", 2));
Serial.println(subStr(record1, " ", 3));

Serial.println("Split record2: ");
Serial.println(subStr(record2, " ", 1));
Serial.println(subStr(record2, " ", 2));
Serial.println(subStr(record2, " ", 3));
}

void loop () {
}

// Function to return a substring defined by a delimiter at an index
char *subStr (char *str, char *delim, int index) {
char *act, *sub, *ptr;
static char copy[MAX_STRING_LEN];
int i;

// Since strtok consumes the first arg, make a copy
strcpy(copy, str);

for (i = 1, act = copy; i <= index; i++, act = NULL) {
//Serial.print(".");
sub = strtok_r(act, delim, &ptr);
if (sub == NULL) break;
}
return sub;

}

If sub is a pointer inside the function then why would we need to have the function pointed to some char instead of just returning *sub ?

"sub" is a pointer to a char, therefore "*sub" is a char.

One thing to remember about char arrays (strings) in C/C++ is that the pointer is a reference to the first element of the array, that is to say that the variable contains the address to the first element of the array, thus why indexes start at 0. If you add the index to the pointer to grab the next element in the array, it works just like putting the index in brackets. i.e. *str or *(str+0) is equivalent to str[0], and *(str+1) is equivalent to str[1]. The parentheses are needed to denote that you're adding to the address that str points to, and not the value. This applies to all arrays, and can be useful to remember.

...the pointer is a reference to the first element of the array...

The rvalue of a pointer can be something other than the first element. A properly initialized pointer can hold only two values: 1) the memory address of a piece of data, or 2) null. However, that rvalue does not have to be the base address of an array:

int val[10];
int *ptr;

ptr = val;       // ptr now points to val[0]
ptr = &val[4];   // ptr now points to 5th element in array

If you want help figuring out complex data definitions (which is not the same as a declaration), see Purdum's Right-Left Rule:

http://jdurrett.ba.ttu.edu/3345/handouts/RL-rule.html

Thank you "DivinityArcane" and "econjack," I will certainly study more and look into your comments in more debt, but for now i think I have sort of figure out the logic and I will ask more once I finish studying. Thank You All. Milad

once I finish studying.

While you are studying, pay some attention to the difference between strtok() and strtok_r. Then, try to explain why you are using the larger, more complicated, thread-safe version on a device that doesn't do threads.

econjack:

...the pointer is a reference to the first element of the array...

The rvalue of a pointer can be something other than the first element. A properly initialized pointer can hold only two values: 1) the memory address of a piece of data, or 2) null. However, that rvalue does not have to be the base address of an array

Just being picky, don't mind me...

Pointers, values, and references do not have r-values or l-values... Expressions do.

In your example, 'ptr', 'val' and 'val[4]' are l-value expressions. You can see this by using the address of operator on them ( which you already have one ), as it only accepts l-value expressions.

Just being picky…

Yep, I agree…

Often I take some liberties when trying to help someone understand a topic. This is what I was trying to get across to the poster…

econjack:
Yep, I agree...

Often I take some liberties when trying to help someone understand a topic. This is what I was trying to get across to the poster...

And what I'm picking at is, you could do all that without reinventing the meaning of certain aspects. Your definition of l/rvalues is only going to confuse someone when things like the compiler spit out errors mentioning l/rvalues.