Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
无法解释C中简单字符串操作的输出_C_String_Pointers - Fatal编程技术网

无法解释C中简单字符串操作的输出

无法解释C中简单字符串操作的输出,c,string,pointers,C,String,Pointers,代码如下: #include<stdio.h> #include<string.h> int main() { char *s = "name"; int n = strlen(s); int i; s = &s[n+1]; for(i=0; i<=n; i++) { printf("%d %c",i,*s);

代码如下:

    #include<stdio.h>
    #include<string.h>
    int main()
    {
       char *s = "name";
       int n = strlen(s);
       int i;
       s = &s[n+1];
       for(i=0; i<=n; i++)
       {
          printf("%d %c",i,*s);
          s++;
       }

        return 0;
    }

我无法理解输出。尽管没有转义序列,为什么要打印%。

这一行
s=&s[n+1]会导致指针指向某个地方。之后,你开始从中读取随机垃圾。显然,随机垃圾包含一些
%
字符。

这一行
s=&s[n+1]会导致指针指向某个地方。之后,你开始从中读取随机垃圾。显然,随机垃圾包含一些
%
字符。

首先分配
s=&s[n+1]
然后使用
*s
访问printf中的超限内存。根据C标准,代码在未定义的行为下运行

s[]
的最大索引可以是包含
\0
的字符串的长度。记住索引值从
0
开始到
(数组/字符串)-1的大小

您的字符串存储在内存中,如下所示:

 s           23   24   25   26   27   28
+----+      +----+----+----+----+----+----+
| 23 |      | n  | a  | m  | e  | \0 |  ? |    
+----+      +----+----+----+----+----+----+
              0     1    2    3   4    5

s points to string "name"  
string length of "name" is 4
length("name")  + 1 = 5 
? means garbage values 
在表达式中
s=&s[n+1]
n+1
是五个
5
,它指向
“name”
字符串的分配内存之外的位置,并且在printf语句中,您使用
*
解引用运算符访问内存会导致无效内存访问,并且此代码在运行时的行为是。这就是为什么在不同的执行过程中代码的行为会有所不同


您的代码可以正确编译,因为它在语法上是正确的,但在运行时,操作系统内核可以检测到对未分配内存的访问。这可能会导致操作系统内核向进程发送导致异常的内核转储信号。(值得注意的是:当操作系统检测到进程违反内存权限时——对有效内存的无效访问给出:SIGSEGV,对无效地址的访问给出:SIGBUS)。在值得一提的情况下,您的程序可以无故障地执行,它会产生垃圾结果

第一次赋值
s=&s[n+1]
然后使用
*s
访问printf中的超限内存。根据C标准,代码在未定义的行为下运行

s[]
的最大索引可以是包含
\0
的字符串的长度。记住索引值从
0
开始到
(数组/字符串)-1的大小

您的字符串存储在内存中,如下所示:

 s           23   24   25   26   27   28
+----+      +----+----+----+----+----+----+
| 23 |      | n  | a  | m  | e  | \0 |  ? |    
+----+      +----+----+----+----+----+----+
              0     1    2    3   4    5

s points to string "name"  
string length of "name" is 4
length("name")  + 1 = 5 
? means garbage values 
在表达式中
s=&s[n+1]
n+1
是五个
5
,它指向
“name”
字符串的分配内存之外的位置,并且在printf语句中,您使用
*
解引用运算符访问内存会导致无效内存访问,并且此代码在运行时的行为是。这就是为什么在不同的执行过程中代码的行为会有所不同


您的代码可以正确编译,因为它在语法上是正确的,但在运行时,操作系统内核可以检测到对未分配内存的访问。这可能会导致操作系统内核向进程发送导致异常的内核转储信号。(值得注意的是:当操作系统检测到进程违反内存权限时——对有效内存的无效访问给出:SIGSEGV,对无效地址的访问给出:SIGBUS)。在值得一提的情况下,您的程序可以无故障地执行,它会产生垃圾结果

s=&s[n+1]是来自越界的赋值。s[n]的值为'\0',在此之后,
s[n+1]
将有一些垃圾值


上面显示的分配是将
s[n+1]
的基址分配给
s
,稍后您将尝试打印此新
s
中的值,因此所有值都将是垃圾。越界访问是未定义的行为。

s=&s[n+1]是来自越界的赋值。s[n]的值为'\0',在此之后,
s[n+1]
将有一些垃圾值

s = &s[n+1];
上面显示的分配是将
s[n+1]
的基址分配给
s
,稍后您将尝试打印此新
s
中的值,因此所有值都将是垃圾。越界访问是未定义的行为

s = &s[n+1];
使
s
指向未知内存。此后引用
s
将调用未定义的行为,当您在
printf
中访问它时,可能会发生任何事情


使
s
指向未知内存。此后引用
s
会调用未定义的行为,当您在
printf
中访问它时,可能会发生任何事情,因为无论何时执行
s[n+1]
,其中
n
是字符串的长度。此外,您正在将此新地址再次分配到
s
。从这个位置开始访问每个索引将导致未定义的行为,因为您不知道这些位置上有什么,并且您是否可以访问它

您可以尝试在定义的字符串之后立即定义另一个字符串

char *s = "name";
char *d = "hello test";
在这种情况下,如果编译器恰好将字符串“name”之后的字符串存储在只读区域中,则可能会打印字符串“hello test”中的字符。这不是保证


底线是,这段代码不正确,会导致未定义的行为。

未定义的行为,因为无论何时执行
s[n+1]
,其中
n
是字符串的长度。此外,您正在将此新地址再次分配到
s
。从这个位置开始访问每个索引将导致未定义的行为,因为您不知道这些位置上有什么,并且您是否可以访问它

s = &s[n+1];
您可以尝试在定义的字符串之后立即定义另一个字符串

char *s = "name";
char *d = "hello test";
在这种情况下,如果编译器恰好将字符串“name”之后的字符串存储在只读区域中,则可能会打印字符串“hello test”中的字符。这不是保证

底线是,这段代码不是正确的
#include <stdio.h>
int main () {
    const char *s = "%d %c";
    int i;
    for (i = 0; i < 5; ++i) {
        printf("%d %c", i, *s);
        s++;
    }
    puts("");
    return 0;
}

/* output is:
0 %1 d2  3 %4 c
*/
0 %
1 d
2  
3 %
4 c
n = 4;
s = &s[n + 1] = &s[5];