C文字,这些存储在哪里

时间:2016-03-17 10:23:41

标签: c

请考虑以下代码:

{{#each $mapped yourCursor true}}
//Getting the next & previous element 
{{$nextEl._id}}
{{$prevEl._id}}
{{/each}}

输出是" erlang"而且我不太清楚为什么...... 我目前的知识表明字符串文字" erlang"和" java"都存储在进程地址空间中,在#34;常量"中。根据这一点,功能f应该改变指针指向" java",但这并没有发生。有人可以解释一下这里发生了什么吗?

6 个答案:

答案 0 :(得分:3)

因为函数参数是在C中通过值传递并且修改被调用者中的参数而不会影响调用者的局部变量。

使用指针修改调用者的局部变量。

#include <stdio.h>

void f(const char ** str) { /* add * to declare pointer */
    *str = "java"; /* add * to access what is pointed */
}

int main (int argc, char * argv[]) { /* use standard signature */
    const char *str = "erlang";
    f(&str); /* add & to get a pointer pointing at str */
    printf("%s\n", str);
}

答案 1 :(得分:1)

C 按值复制。当str作为参数传递给f时,会先复制,并且该副本实际上会传递给f。将"java"分配给该副本不会对str中的原始main执行任何操作。

答案 2 :(得分:1)

由于您传递的值意味着按值调用,如果您传递这样的引用,您将看到输出为java:

#include <stdio.h>

void f(const char ** str) {
    *str = "java";
}

void main (int argc, char * argv[]) {
    const char *str = "erlang";
    f(&str);
    printf("%s\n", str);
}

输出:

rabi@rabi-VirtualBox:~/rabi/c$ gcc ptr1.c 
rabi@rabi-VirtualBox:~/rabi/c$ ./a.out 
java

答案 3 :(得分:1)

函数参数是其局部变量。您可以通过以下方式设想函数定义及其调用(我将参数名称从str更改为s以获得清晰度)

void f(/*const char * s*/) {
    const char *s = str;
    s = "java";
}
//...
const char *str = "erlang";
f(str);

局部变量s的任何更改都不会影响用作参数的原始变量str。变量str本身没有变化。

如果要在函数中更改参数,则应通过引用传递参数。例如

#include <stdio.h>

void f( const char ** str ) 
{
    *str = "java";
}

int main( void ) 
{
    const char *str = "erlang";
    f( &str );
    printf( "%s\n", str );
}    

程序输出

java

考虑到根据C标准函数main应该有返回类型int。

答案 4 :(得分:1)

  

有人可以解释一下这里发生了什么吗?

许多好的答案都已经准备就绪但我还是试着通过略微修改的代码来尝试执行详细的步行。

考虑MongoClient.save(...)会发生什么。 f("Hello World")字符串文字。它初始化"Hello World" 数组。当数组传递给函数或分配给指针时,它将转换为数组的第一个元素的地址。 char会在其f()中收到'H'地址的副本。 #1打印str"Hello World"被重新分配到str的地址。 #2打印'j'。该函数在不影响 "java"的情况下结束

使用"Hello World"str = "erlang"会收到str的地址。 #3打印'e'。在函数调用中,"erlang"&#39; main()的值将复制到str&#39; s f()。 #1打印str。与以前一样,"erlang"会重新分配到str的地址。 #2打印'j'。该函数在不影响 "java" main()的情况下结束。 #4打印str

"erlang"

输出

#include <stdio.h>

void f(const char * str) {
  printf("f()    before str='%s'\n", str); // #1
  str = "java";
  printf("f()    after  str='%s'\n", str); // #2
}

int main(void) {
  f("Hello World");
  puts("");

  const char *str = "erlang";
  printf("main() before str='%s'\n", str); // #3
  f(str);
  printf("main() after  str='%s'\n", str); // #4

  return 0;
}

至于OP的问题:

  

C文字,这些存储在哪里?

字符串文字的位置未在C中定义。它可能使用&#34;进程地址空间,在常量&#34;部分中,它可能不会。重要的是形成一个数组,并在赋值给f() before str='Hello World' f() after str='java' main() before str='erlang' f() before str='erlang' f() after str='java' main() after str='erlang' 时给出第一个字符的地址。进一步的细节:写入这个地址是未定义的行为(UB),它可能&#34;工作&#34;,失败,seg-fault等。

答案 5 :(得分:0)

如果您更改了f ...

的参数名称,这将更加明显
#include <stdio.h>

void f(const char * foo) {
    foo = "java";
}

int main (int argc, char * argv[]) {
    const char *str = "erlang";
    f(str);
    printf("%s\n", str);
}

foo是与str不同的变量。它具有不同的名称,不同的范围,并且可以包含不同的值。对foo的更改不会传播到str。如果您想在str内修改f,则需要使f看起来像这样:

void f(const char **foo) {
    *foo = "java";
}

...并将str的指针传递给f,如下所示:f(&str);

您是否注意到我将void main更改为int main的方式? main入口点(不包括等价物)只有两个签名,这些签名由标准保证是可移植的:

int main(void) { /* ... */ }

......和......

int main(int argc, char *argv[]) { /* ... */ }

无论哪种方式,main 始终都会返回int(或等效内容)。这不应该给你带来太大的不便,比如在C99(任何比15岁更新的半合适的编译器)和C11那里this little gem允许你从return 0;省略main

  

如果main函数的返回类型是与int兼容的类型,则从初始调用返回main函数等效于调用exit函数,并将main函数返回的值作为其参数; 11)到达终止main函数的}返回值0。

因此,如果有的话,使用int main入口点的代码不仅仅是可移植的,而且比使用非可移植void main入口点的代码短一个字节。