2

As far as I know, you cannot modify a Array variable

How come this code run without any error. Is there anything I am missing out here. (It's not about why there is 'L-VALUE REQUIRED' error , it's about why there isn't.)

    #include<stdio.h>
int strlens(char *s);
void main(){
    char s[]="get me length of this string ";

    // s++ ; this would give 'L-VALUE REQUIRED ERROR'

    printf("%d",strlens(s));    
}
int strlens(char s[]){
    int i;
    for(i=0; *s!='\0';++i, ++s) ; //++s:  there is NO 'L-VALUE REQUIRED ERROR'
    return i;


}
11
  • s is not an array name in strlens, it's a pointer. Arrays and pointers are distinct types. Commented Dec 11, 2017 at 7:22
  • 1
    When you do char s[], the s is a name (compile time symbol; has no run-time significance). It is not allocated any space and hence does not store an address. If you want to do pointer arithmetic, you need to store the address somewhere, don't you? In case of the function argument, the address of your original character array was pushed onto the stack and your function parameter s refers to that. Therefore, the function parameter s has space allocated for it where it stores the address. You can now do pointer arithmetic as there is something to which you can do arithmetic on. Commented Dec 11, 2017 at 7:38
  • 2
    @Yashas: "Array arguments behave as pointers": they do not just "behave as pointers", they are pointers. Commented Dec 11, 2017 at 8:27
  • 1
    The error message is misleading. s is a lvalue in main. It is not a modifiable lvalue though. Commented Dec 11, 2017 at 8:47
  • 2
    Just to state this explicitly: int strlens(char s[]); is 100% equivalent to int strlens(char * s); It is interchangeable and the compiler ought to create the exact some code for both. Commented Dec 11, 2017 at 8:55

3 Answers 3

4

A quirk of the C language that is well-known to seasoned C programmers, but trips up new C coders to no end, is that arrays are "pass by reference". Generally speaking, an array name used in most expressions will "decay" to the address of its first element. Functions carry that to an extreme case, where the array syntax in the function parameter is actually an alias for the pointer type itself.

This is described in paragraph 7 of c11's §6.7.6.3 Function declarators:

A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation.


Historically, this quirk was an attempt to maintain behavioral compatibility to C's predecessors, B and BCPL, and efficient structure layout. C's predecessor had a semantic for arrays in that its physical layout was actually a pointer that got dynamically allocated and initialized at runtime. When passed to a procedure, the pointer semantic was a natural adoption. Dennis Ritchie invented the notion of allowing the array syntax represent the actual address of the array, and then maintained the pointer semantic when passed to a function. Thus, the inventor of the C language considered this quirk a novel solution to a real world problem (semantic compatibility).

References: The Development of the C Language

Sign up to request clarification or add additional context in comments.

10 Comments

arrays are "pass by reference" -- you mean the correct thing of course and the standard quote is the relevant one, still I don't like to put it that way -- there's just no "pass by reference" in C, but pointers allow the programmer to kind of "simulate" it. I would therefore better state that arrays just can't be passed at all and the rules for expression evaluation and type adjustment (together often called "arrays decay to pointers", which isn't in the standard either) help to "easily" pass a pointer instead.
I think the more precise terms would be pass by pointer/by address.
@FelixPalmen: The quotes are meant to impart that I am not using the term literally. However, the notion of "pointers are references" was imparted to me from the Ritchie's paper The Development of the C Language. Decay was a term I picked up as I was becoming proficient in C. I probably saw it in the C-faq. It should have been in quotes too, and I have made that edit.
Agree with @FelixPalmen Arrays are not pass by reference. If they were, it would imply that changing the "array reference" in the callee would change the array in the caller. i.e. the array would actually be a different location in memory. The correct point is that arrays are not passed at all.
@JeremyP: That interpretation (the array would actually be a different location in memory) is not the usual interpretation of what changing a function argument passed by reference would mean. You are conflating the pointer argument as if the pointer object itself is what is passed by reference. Dennis Ritchie was attempting to simulate pass by reference for arrays to avoid stack burden.
|
2

This line

char s[]="get me length of this string ";

defines a character array. s is not a pointer, it evaluates to an address (when fed to a pointer for instance, or when accessing a value like s[i] equivalent to *(s+i)), or represents the space occupied by the array (eg in sizeof(s))

But in a function signature like this

int strlens(char s[]){

char s[] is equivalent to char *s, and you can treat s like a pointer.

Comments

2

char arr[] = "asds"

Here, arr is just a name. It refers to a memory location but is not a pointer. The compiler substitutes the address directly wherever arr is used. It is not a pointer because unlike pointers, it does not have any space allocated to store an address. It is a mere compile time symbol. Hence, at run-time there is nothing on which you can do pointer arithmetic on. If you had to increment something, that something should exist at run-time.

More details:

Basically, the literal "asds" is stored in your executable and the compiler knows where exactly it is (well, the compiler is placing it in the executable, so it should know?).

The identifier arr is just a name to that location. As in, arr is not a pointer, i.e: it does not exist in memory storing an address.


void func(char arr[])

In case of a function argument, the arr does exist in memory at run-time because the arguments are pushed onto the call stack before making the function call. Since arrays are passed by reference, the address of the first element of the actual parameter is pushed onto the call stack.

Therefore, arr is allocated some space on the stack where it stores the address to the first element of your actual array.

Now you have a pointer. Hence you can increment (or do any pointer arithmetic on it).

4 Comments

"like a pointer" -> it is a pointer, period.
"It does not have any space allocated for it" as it stands this sentence is wrong. arr very well "uses" memory, namly 4+1 chars.
@alk I updated it but it doesn't look nice. I don't know how to phrase it into a simple proper sentence.
It's better. BTW, I didn't DVed.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.