The correct version of your call is ft_strlowcase(str1). However, that still perpetrates undefined behavior because the string literal object created by str1 = "AbCdEfGhI" is being modified. String literals are part of the program image; modifying a string literal is de facto self-modifying code, whose behavior is not defined by ISO C.
This is not actually a big difference between dynamic languages and C here; ANSI Common Lisp is the same way with regard to modifying literal objects.
By the way, your C compiler should be warning you that the ft_strlowcase(&str1) call is ill-typed: it passes a char ** pointer to a function which expects char *.
Now regarding this:
//char str1[] = "AbCdEfGhI"; //WORKING
Yes that will work for two (and a half) reasons.
Firstly, "AbCdEfGhI" is no longer a literal object here, but only initializer syntax. The object is the str1 array, and ""AbCdEfGhI" specifies its size and initial contents. This str1 array is not a string literal; it is mutable. It is well defined to do something like str[0]++.
Because str1 is an array, the expression &str1 produces a "pointer to array" value. But this pointer points to the same address as the first character of that array. So that is to say, because str is an array, str, &str[0] and &str are all the same pointer. The first two have the type char *, whereas &str has the type char (*)[10]: pointer to an array of 10 char. The expression ft_strlowcase(&str1) still requires a diagnostic, which makes your program undefined: you are asking the compiler to convert one pointer type to an incompatible type without a cast. However, if the compiler simply emits the diagnostic and then supplies the conversion as if there were a cast, then you will get the apparently correct behavior. You need ft_strlowcase(str1) (vastly preferred) or else ft_strlowcase((char *) &str1) (provide the cast, so no diagnostic is required). Programs that require a diagnostic have undefined behavior if they are translated and executed anyway!
Lastly, your ft_strlowcase function is verbose. More idiomatic C code looks like this, among other possibilities:
char *ft_strlowcase(char *str)
{
for (char *ptr = str; *ptr; ptr++) {
if (*ptr >= 'A' && *ptr <= 'Z')
*ptr += 32;
}
return str;
}
Believe it or not, is more readable to experienced C programmers, because it condenses together several well-understood, well-worn idioms into a concise clump.
In your original code, this is particularly something that should be avoided:
int i;
i = 0;
For no reason at all, you've declined an obvious opportunity to define an initialized variable:
int i = 0;
Initialization should always be preferred to assignment. They are different. Initialization means that an object is "born" into the world with a value; at no point in its program-visible existence does not not have a value. In C, we can define a local variable object without initializing it, which leaves it "indeterminately-valued". That habit creates the risk of using an indeterminately-valued object, which is undefined behavior.
ft_strlowercase(str1);, butstr1 = "AbCdEfGhI"setsstr1to point to a string literal which is not modifiable. Your "WORKING" option is the right way to go. You can't accomplish this within one expression.isalpha()andtolower(). The only guarantee about the printable character set is that'0'to'9'are consecutive and in order.char* str = "AAA";andchar str[] = "AAA"?charis nonnegative.