为什么没有“需要的价值”'增加数组名称时出错

时间:2017-12-11 07:20:26

标签: c arrays lvalue

据我所知,你无法修改数组变量

为什么这段代码运行没有任何错误。 我在这里错过了什么吗(这不是为什么会出现L值和错误,而是关于为什么没有。)

    #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;


}

3 个答案:

答案 0 :(得分:4)

C语言的一个奇怪之处,对于经验丰富的C程序员而言是众所周知的,但是对于新的C编码器而言,这种数组是“通过引用传递”。一般来说,大多数表达式中使用的数组名称将“衰减”到其第一个元素的地址。函数将其带到极端情况,其中函数参数中的数组语法实际上是指针类型本身的别名。

c11的§6.7.6.3 函数声明符第7段对此进行了描述:

  

参数声明为'' type ''的数组应调整为''限定指针    type '',其中类型限定符(如果有)是在[]内指定的类型限定符。   数组类型推导。

从历史上看,这个怪癖是为了保持与C的前辈B和BCPL的行为兼容性以及高效的结构布局。 C的前身对数组有一个语义,因为它的物理布局实际上是一个在运行时动态分配和初始化的指针。当传递给一个过程时,指针语义是一种自然的采用。 Dennis Ritchie发明了允许数组语法表示数组的实际地址,然后在传递给函数时保持指针语义的概念。因此,C语言的发明者认为这个怪癖是一个解决现实世界问题(语义兼容性)的新颖解决方案。

参考文献: The Development of the C Language

答案 1 :(得分:2)

这一行

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

定义一个字符数组。 s不是指针,它计算为一个地址(例如,当被提供给指针时,或者当访问类似于s[i]的{​​{1}}等值时),或表示占用的空间数组(例如在*(s+i)

但是在像这样的函数签名中

sizeof(s)

int strlens(char s[]){ 等同于char s[],您可以将char *s视为指针。

答案 2 :(得分:2)

char arr[] = "asds"

在这里,arr只是一个名字。它指的是内存位置,但不是指针。编译器直接在使用arr的地方替换地址。它不是指针,因为与指针不同,它没有分配任何空间来存储地址。它只是一个编译时符号。因此,在运行时,您无法对其进行指针运算。如果你必须增加某些东西,那么某些东西应该在运行时存在。

更多详情:

基本上,文字“asds”存储在你的可执行文件中,编译器知道它到底在哪里(好吧,编译器把它放在可执行文件中,所以它应该知道吗?)。

标识符arr只是该位置的名称。如同,arr不是指针,即:在存储地址的存储器中不存在

void func(char arr[])

在函数参数的情况下,arr在运行时确实存在于内存中,因为在进行函数调用之前,参数被推送到调用堆栈。由于数组是通过引用传递的,因此实际参数的第一个元素的地址被推送到调用堆栈。

因此,arr在堆栈上分配了一些空间,它将地址存储到实际数组的第一个元素。

现在你有一个指针。因此,您可以递增(或对其执行任何指针运算)。