我来自 JS,我仍然在努力理解指针的概念,为此,我创建了一个函数来小写字符串。
char *ft_strlowcase(char *str)
{
int i;
i = 0;
while (str[i])
{
if (str[i] >= 'A' && str[i] <= 'Z')
{
str[i] = str[i] + 32;
}
i++;
}
return (str);
}
Run Code Online (Sandbox Code Playgroud)
现在,我想测试它,在我的逻辑中,我可以传递一个指向我的函数的指针,如下所示:
int main(void)
{
//char str1[] = "AbCdEfGhI"; //WORKING
//char *str1 = "AbCdEfGhI"; //NOT WORKING
//char *str1; //NOT WORKING
//str1[] = "AbCdEfGhI"; //NOT WORKING
char *str1; //NOT WORKING
str1 = "AbCdEfGhI"; //NOT WORKING
printf("Lowercase : %s\n", str1);
ft_strlowcase(&str1);
printf("Uppercase : %s\n", str1);
}
Run Code Online (Sandbox Code Playgroud)
但它不起作用,我让它起作用的唯一方法是在一行中传递一个数组声明。我错过了什么 ?我可以让它与指针合成一起工作而不需要任何复杂的函数(memloc ...)吗?
您的通话的正确版本是ft_strlowcase(str1). 但是,这仍然会产生未定义的行为,因为创建的字符串文字对象str1 = "AbCdEfGhI"正在被修改。字符串文字是程序映像的一部分;修改字符串文字实际上是自修改代码,其行为未由 ISO C 定义。
这实际上并不是动态语言和 C 之间的很大区别;ANSI Common Lisp 在修改文字对象方面采用相同的方式。
顺便说一句,您的 C 编译器应该警告您该ft_strlowcase(&str1)调用是错误类型的:它传递了一个char **指向需要char *.
现在关于这一点:
//char str1[] = "AbCdEfGhI"; //WORKING
Run Code Online (Sandbox Code Playgroud)
是的,这有两个(半)原因。
首先,"AbCdEfGhI"这里不再是文字对象,而只是初始化语法。该对象是str1数组,并""AbCdEfGhI"指定其大小和初始内容。该str1数组不是字符串文字;它是可变的。它被明确定义为做类似的事情str[0]++。
因为str1是一个数组,所以表达式&str1产生一个“指向数组的指针”值。但该指针指向与该数组的第一个字符相同的地址。也就是说,因为str是数组,str、&str[0]都是&str同一个指针。前两个的类型char *为:指向 10 数组的&str指针。该表达式仍然需要诊断,这会使您的程序未定义:您要求编译器将一种指针类型转换为不兼容的类型而不进行强制转换。但是,如果编译器只是发出诊断信息,然后像进行强制转换一样提供转换,那么您将获得明显正确的行为。您需要(非常首选)或否则(提供演员表,因此不需要诊断)。如果无论如何翻译和执行需要诊断的程序,则它们具有未定义的行为!char (*)[10]charft_strlowcase(&str1)ft_strlowcase(str1)ft_strlowcase((char *) &str1)
最后,你的ft_strlowcase函数很冗长。更惯用的 C 代码如下所示,还有其他可能性:
char *ft_strlowcase(char *str)
{
for (char *ptr = str; *ptr; ptr++) {
if (*ptr >= 'A' && *ptr <= 'Z')
*ptr += 32;
}
return str;
}
Run Code Online (Sandbox Code Playgroud)
不管你相信与否,它对于经验丰富的 C 程序员来说更容易阅读,因为它将几个易于理解、陈旧的习惯用法浓缩成一个简洁的块。
在您的原始代码中,这是特别应该避免的事情:
int i;
i = 0;
Run Code Online (Sandbox Code Playgroud)
您毫无理由地拒绝了定义初始化变量的明显机会:
int i = 0;
Run Code Online (Sandbox Code Playgroud)
初始化应始终优先于赋值。他们是不同的。初始化意味着一个对象“诞生”到这个世界上时就带有一个值;在其程序可见的存在中,任何时候都没有价值。在 C 中,我们可以定义局部变量对象而不对其进行初始化,这使其成为“不确定值”。这种习惯会带来使用不确定值对象的风险,这是未定义的行为。