2

I'm currently in my 1st year of programming and have solved the problem to some code using string arrays but have no idea why it worked. We are still studying pointers but I wanted to try arrays for a bit.

I wanted to pass the value of a string from the main function, to pass to another function, to compare it with another string. If the two strings are equal, it prints "equal" otherwise, it prints "not equal". Although I've solved the problem , I'm confused by how this works:

       char name1[100];
       scanf("%s",name1);
       getname(name1[0]); 

return 0;
}

void getname(char name1[0]){

    printf("Name1 is %s",name1);

    return;
}

If you run it this way, it will not run the function and will return a garbage value. However, if I change

getname(name1[0]);

into

getname(&name1[0]);

it works perfectly fine, why is this?. Secondly, in the "getname" function. since I had to add the ampersand/address to the function call, I was taught that I needed to add an asterisk next to the variable to avoid getting the actual address but to get the actual value. Why is it in

printf("Name1 is %s",name1);

it is able to print the string perfectly fine without needing it to be:

printf("Name1 is %s",*name1);
codeorig12
  • 43
  • 4
  • To be sure I understand, `name1` is declared as `char name1[100]`? How did you assign to it? – Schwern Oct 23 '19 at 01:07
  • I think the needed info is already in your question, but ideally please turn your shown code parts into a [mre]. – Yunnosch Oct 23 '19 at 01:11
  • 2
    Possible duplicate of [What is array decaying?](https://stackoverflow.com/questions/1461432/what-is-array-decaying) – Yunnosch Oct 23 '19 at 01:13

1 Answers1

2

void getname(char name1[0]) formally says you're going to pass a character array of zero size (side note: zero size arrays are not allowed in standard C but compilers sometimes allow them).

What it really says is you're going to pass a character pointer, a char *. The size is ignored. It's equivalent to the less confusing: void getname(char *name1).

In addition, since you're not going to alter the string inside function you can declare it const char * and be warned if you try to alter it.

#include <stdio.h>

void getname(const char *name1){
    printf("Name1 is %s",name1);

    return;
}

int main() {
    char name[100] = "foo";
    getname(name);
}

getname(name1[0]); gives you garbage because instead of passing in the pointer to the start of the string, you're passing in the first character of the string. If the string is "Yarrow Hock" you're trying to pass in Y which is really the number 89. C will then try to read what's at memory address 89 which is probably garbage.

You can see this if you print the memory address of name1 using %p.

void getname(const char *name1){
    printf("Name1 points to %p\n",name1);
    printf("Name1 is %s\n",name1);

    return;
}

You should get a warning like:

incompatible integer to pointer conversion passing 'char' to parameter of
      type 'const char *'; take the address with & [-Wint-conversion]

Which leads us to a very important thing: compiler warnings. They are extremely important and by default they are off. Turning them on will save you hours of head scratching. There are a bewildering array of possible warnings and they're slightly different from compiler to compiler. Here's what I use with clang.

-Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c11 -pedantic

You can read what each of these mean in Diagnostic flags in Clang. And yes, "-Wall" does not mean "all warnings".

A good code editor, I recommend Atom, will also give you warnings as you edit.


getname(&name1[0]); works because it is equivalent to getname(name1 + 0) which is equivalent to getname(name1). name1[0] is the first character of the string. & gets its address, which is the start of the string just like name1 itself. printf then prints characters until it hits a null byte.

You can see this by trying getname(&name1[1]), or more directly with pointer arithmetic as getname(name1 + 1). This will pass in the address of the second character in name1. If name1 = "Yarrow Hock" it will print arrow Hock. This is a valid technique for skipping prefixes without altering the string.

Schwern
  • 153,029
  • 25
  • 195
  • 336