C 将字符串文本作为定义为指针的函数参数传递

C 将字符串文本作为定义为指针的函数参数传递,c,pointers,C,Pointers,我正在阅读Kernighan和Richie的《C编程语言》中有关数组和指针的章节 他们举了一个例子: /* strlen:  return length of string s */ int strlen(char *s) {     int n;     for (n = 0; *s != '\0'; s++)         n++;     return n; } 然后说: “因为s是指针,增加它是完全合法的;s++对调用strlen的函数中的字符串没有影响,而只是增加strlen的指

我正在阅读Kernighan和Richie的《C编程语言》中有关数组和指针的章节

他们举了一个例子:

/* strlen:  return length of string s */
int strlen(char *s)
{
    int n;

    for (n = 0; *s != '\0'; s++)
        n++;
    return n;
}
然后说:

“因为
s
是指针,增加它是完全合法的;
s++
对调用
strlen
的函数中的字符串没有影响,而只是增加strlen的指针的私有副本。这意味着调用

strlen("hello, world");  /* string constant */
strlen(array);           /* char array[100]; */
strlen(ptr);             /* char *ptr; */
所有的工作。”

除了第一个调用示例外,我感觉我理解了所有这些:为什么或如何将字符串literal
“hello,world”
视为
char*s
?这怎么是指针?函数是否将此字符串文字指定为其局部变量
*s
的值,然后使用
s
作为数组名/指针?

“你好,世界”

是字符的数组(类型是字符[13])。表达式中
char
数组的值是指向
char
的指针。指针指向数组的第一个元素(即
“hello,world”
的值是
和“hello,world”[0]
)。

请注意:

  • 指针(基本上)是指向内存地址的值
  • “hello,word”
    这样的静态字符串存储在内存中的某个位置
因此,指针可以像指向存储在内存中的任何其他(动态)结构(如字符数组)一样简单地指向静态字符串。与提供的其他示例实际上没有区别

函数是否将此字符串文字指定为其局部变量*s的值 然后使用s作为数组名/指针


要理解像“Hello World”这样的字符串是如何转换为指针的,重要的是要理解,字符串实际上是十六进制数据,从一个地址开始,一直移动到找到一个
NULL

这意味着,每个字符串常量,比如“Hello World”,都存储在内存中的某个地方

可能是:

0x10203040 : 0x48 [H]
0x10203041 : 0x65 [e]
0x10203042 : 0x6C [l]
0x10203043 : 0x6C [l]
0x10203044 : 0x6F [o]
0x10203045 : 0x20 [' ']
0x10203046 : 0x57 [W]
0x10203047 : 0x6F [o]
0x10203048 : 0x72 [r]
0x10203049 : 0x6C [l]
0x1020304A : 0x64 [d]
0x1020304B : 0x00 [\0]
因此,当使用内存中的上述值调用此函数时,[左侧是地址,后跟“:”,右侧是字符的ascii值]

int strlen(const char *s)
{
    int n;

    for (n = 0; *s != ′\0′; s++)
        n++;
    return n;
}

strlen("Hello World");
此时,传递到strlen的是值
0x10203040
,它是字符数组的第一个元素的地址


注意,地址是按值传递的。。因此,
strlen
拥有自己的“Hello World”地址副本。从
n=0
开始,在内存中找到
\0
之后,我递增
n
,同时递增
s
中的地址(然后递增为
0x10203041
),依此类推,直到它在地址
0x1020304B
处找到
\0
,并返回字符串长度。

如同一页第一段所述(第99页,K&R2):

根据定义,数组类型的变量或表达式的值为 数组的元素0的地址。“

“hello,world”的值是“h”的地址

char str[] = "Hello, world";
strlen(str);
C中的字符串是以NULL('\0')结尾的字符数组,这意味着它应该在内存中的某个位置

那么,如上所述发送存储字符串和如下所述直接发送存储字符串有什么区别呢

strlen("Hello, World");
答案是两者都是相同的,但是字符串存储在哪里以及如何处理,编译器和堆栈就来了

编译器在编译时将字符串推入堆栈并发送堆栈中的起始地址(char*),调用函数看到指针并访问字符串

编译器还会在函数的exist之后添加代码,以将堆栈恢复到正确的位置,从而删除创建的临时字符串
注意:以上内容取决于编译器的实现,但大多数编译器都是这样工作的

关于字符串、数组、指针及其关系的一些非常好的问题/答案。祝贺你至少在这个主题上做了一些研究,这比任何人在发布关于这个主题的问题之前做的都要大得多。写得好的问题。还要注意,K&R在良好的编程实践方面缺乏足够的知识。将字符串传递给不修改它的函数时,应将参数声明为
const char*s
。当传递字符串文本时,这一点尤为重要。如果您的函数试图写入
*s
,您将调用未定义的行为,程序可能会崩溃。感谢大家将其制作成如此出色的线程!很难/不可能找到一个公认的答案。带着你的答案,我回去读了书中这个例子前面的部分。我想我以前没有注意到的关键句子是
,根据定义,数组类型表达式的变量的值是数组的元素零的地址。因此,当我在函数中使用字符串文字作为参数时,我传递的不是字符串文字本身,而是“类型数组”,它是指向字符串文字中第0个索引的指针,这是一个数组。谢谢你!事实上,我在发帖前自己回答这个问题时遇到了这个问题。更多关于您提到的内容(使用
const char*s
而不是
char*s
)可以在“Yes”中找到,因为字符串文字是一个数组。根据定义,数组类型表达式的变量的值是数组的元素零的地址,因此数组的值是其第一个元素的地址。此第一个地址作为本地函数变量分配给
s
。谢谢Aniket。将参数签名更改为
const char*s
是否会阻止此函数或具有此类签名的任何函数在本地操作指针变量?
const
是否本质上转动