4

I have the following function used to count spaces in a string:

int countSpace(char *str) {
        int nSpaces = 0;
        while (*(str) != '\0') {
                if (*(str) == ' ') {
                        nSpaces++;
                }
                str++;
        }
        return nSpaces;
}

I use this function like this:

char a[]="Hello ";
printf("%d", countSpace(a));

My question is, when I do this: printf("%s", a);, after calling countSpace, why is that a not pointing at the very end? I mean, I have incremented the pointer inside the countSpace function, but outside seems to be pointing at the very beginning still. Why is that?

I know that the changes that I make in *str inside the countSpace function will affect the outside, so that if for example I do: str[0] = 'p', outside of the function the value of a will be pola. So, I don't understand why the pointer is still pointing at the very beginning even though inside the function I have made it move forward.

StarTrek18
  • 323
  • 4
  • 15

5 Answers5

4

Because C passes arguments by value

  int countSpace(char *str)
                      ^^ 
            This pointer is a copy of the pointer you pass in.

Initially, your str variable points to the same thing as the pointer you pass to your function, but inside countSpace() you are just incremeting the local copy of that pointer.

nos
  • 223,662
  • 58
  • 417
  • 506
  • But, if it's a copy how come inside of that function I can do str[2] = 'l', and that will change the value outside? – StarTrek18 Mar 30 '14 at 19:26
  • 1
    @StarTrek18 The pointer is a copy, however it's pointing to the same address in memory so if you change the data the changes remain after the function has returned, even though the pointer hasn't changed. – dutt Mar 30 '14 at 19:31
  • 1
    @StarTrek18 -- the **pointer** is copied by value. The memory region, it points to, is not copied at all. Think of the pointer being an integer value (the address of the object it points to). That integer is passed by value. – Dirk Mar 30 '14 at 19:31
  • 1
    @StarTrek18 So if you want to change the pointer you need to make a pointer to the pointer: char** str – dutt Mar 30 '14 at 19:33
1

C is pass-by-value, so when you pass the pointer to countSpaces it makes a copy of the value of the pointer (mind you, just the pointer not what it points to). Just like any other local value: any changes made to it inside the function are not reflected outside.

Any changes to the what is pointed to by the pointer inside the function would be seen outside the function.

For example: we take the address of a, store it in a pointer p and print that as a pointer (to see the memory-address it holds):

char * p = a;
printf(" p = %p\n", p); // This will not print the string, but the address where it starts

and pass that to countSpaces (this is equivalent to passing a to countSpaces):

countSpaces(p);

Now inside, print str as a pointer:

printf(" str: %p\n", str);

You'll see that both the values are the same, this makes sense since it was copied to countSpaces. However, if you print the address of p (outside countSpaces) and the address of str (inside). You'll see that they are different:

printf("&str: %p\n", &str);

printf("&p: %p\n", &p);

Therefore, countSpaces can change what str and p (and a) point to, but not the pointers themselves: they are copied into new variables.

Kninnug
  • 7,992
  • 1
  • 30
  • 42
1

The variable a is not changed by the function.

Understanding where are vars and values in memory helps understand what is happening with pointers. As well as helping later with debugging.

Do %p printf of a and str and you will see memory address they are pointing at.

printf("a var %p", &a);
printf("a content %p", a);
printf("str var %p", &str);
printf("str content %p", str);

Example where things are in memory assuming baby 2 byte int and ptrs.

# c compiler/linker will put string values in global memory

#Addr #Value
#0020 Hello \0
#0027 %d\0
#0030 . .

Stack memory. var a is in stack mem (assume in stack of main function) (actually compiler could place vars into registers but same result is yielded)

#stack-main a is a char ptr. 
#&a=0100, value of a=0020
#Addr #Value
#0100 0020

#when countSpaces is just called
#code return addr pushed to stack
#Addr #Value
#0102 0222
#space on stack for return of int
#0104 0000
#value of a put on stack (this is str)
#0106 0020
#local vars of countSpaces 
# int nSpaces
#0107 0000

After countSpaces returns stack looks like:

#&a=0100, value of a=0020
#Addr #Value
#0100 0020

#Addr #Value
#code return addr
#0102 0222
#space on stack for return of int
#0104 0001
#value of a put on stack (this is str)
#0106 0026
#local vars of countSpaces 
# int nSpaces
#0107 0001
gaoithe
  • 4,218
  • 3
  • 30
  • 38
0

str is a copy of the pointer that was passed to the parameter list of the function. It is not different from, say, an int parameter.

So, a is left unchanged.

SJuan76
  • 24,532
  • 6
  • 47
  • 87
  • I don't get it, because if inside the function I do ``str[3] = 'P';``, and I print the value outside, it actually has changed its value. – StarTrek18 Mar 30 '14 at 19:28
  • Because the `ptr` is a copy of `a`. So, they are two pointers that point to the same memory location. If you change the contents of that memory location, the changes are accessed from both pointers. – SJuan76 Mar 30 '14 at 19:30
0

str is a pointer to the string and is passed by value to the function.

When you change str inside the function the original variable passed from outside the function doesn't change.

Of course as str is a pointer it allows you to change the char it points to.

If you want to change the outside str from inside your function you have to pass a pointer to str, in other words a pointer to a pointer to your string (the first character).

The code becomes:

int countSpace(char **str) {
        int nSpaces = 0;
        while (**(str) != '\0') {
                if (**(str) == ' ') {
                        nSpaces++;
                }
                *str++;
        }
        return nSpaces;
}

use this function like this:

char a[]="Hello ";
printf("%d", countSpace(&a));
Paolo
  • 15,233
  • 27
  • 70
  • 91