In a C function call, all arguments are passed by value, so the function has a copy of them. Therefore it's never possible that the function changes an argument. Sounds like contradicting what you observe here, but it isn't:
Arrays in C are somewhat special. An array identifier is evaluated to the address of the array's first element (aka: a pointer) in almost any place (exceptions include the sizeof
operator). It's impossible to assign an array, and it is impossible to pass an array (as a function argument or as a return value).
Again, this looks contradicting, but there's another rule for function declarations: If a function declaration includes an array type, this is automatically adjusted to the corresponding pointer type. So your function
int getlines(char s[], int lim);
is in fact the following function: *)
int getlines(char *s, int lim);
The effect of adjusting the type in a function declaration and evaluating the identifier of an array as a pointer together is often expressed as the array decays as a pointer. What really gets passed to your function is a pointer, not an array. Indexing that pointer, the code in the function accesses the original array. The pointer is of course passed by value and your function doesn't change this pointer, but it can change what it points to.
*) stylistic note: I prefer to always write the function declarations with pointer types, because this is what the compiler sees anyways, so it avoids confusion. Of course, some argue it's good to write the array type as it documents the intent that this function should be passed a pointer to an array.