未定义行为在尝试打印数组元素时发生

huangapple go评论64阅读模式
英文:

undefined behaviour when trying to print array elements

问题

这段代码的目标是通过printf打印出二维数组中的字符串,但输出结果确实很奇怪。输出如下:

> 
> abcd
> efgh
> klmn
> �=3�
> 
> 
> 
> 
> 
> 
> I8V
> 
> 
> 3�
> 
> �
> ��.m�
> �
> 
> ?3�
> 
> zI8V
> 
> 
> ��HU�yԁB��7x
> �yԁB��7x
> B��7x
> 
> 
> 
> 
> 
> 
> 
> �
> 
> ���
> 
> 
> 
> �yI8V
> 
> I8V
> 
> 
> 
> 
> 
> 
> 
> 
> 
> ��p��C�x86_64
> �C�x86_64
> x86_64
> 4
> 
> 
> /strcat
> at
> ELL=/bin/bash
> bin/bash
> ash
> ESSION_MANAGER=local/kali:@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
> N_MANAGER=local/kali:@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
> AGER=local/kali:@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
> local/kali:@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
> /kali:@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
> :@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
> p/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
> E-unix/836,unix/kali:/tmp/.ICE-unix/836
> x/836,unix/kali:/tmp/.ICE-unix/836
> ,unix/kali:/tmp/.ICE-unix/836
> /kali:/tmp/.ICE-unix/836
> :/tmp/.ICE-unix/836
> /.ICE-unix/836
> -unix/836
> /836
> WINDOWID=0
> WID=0
> 
> CCESSIBILITY=1
> IBILITY=1
> TY=1
> COLORTERM=truecolor
> TERM=truecolor
> truecolor
> olor
> XDG_CONFIG_DIRS=/etc/xdg
> ONFIG_DIRS=/etc/xdg
> _DIRS=/etc/xdg
> =/etc/xdg
> /xdg
> XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0
> ESSION_PATH=/org/freedesktop/DisplayManager/Session0
> N_PATH=/org/freedesktop/DisplayManager/Session0
> H=/org/freedesktop/DisplayManager/Session0
> g/freedesktop/DisplayManager/Session0
> edesktop/DisplayManager/Session0
> top/DisplayManager/Session0
> isplayManager/Session0
> yManager/Session0
> ger/Session0

这种输出是由于代码中的错误导致的。循环条件 x<=x+2 是不正确的,它导致了无效的内存访问。正确的循环条件应该是 x<=names+2,这样就可以正确迭代数组并打印字符串。

希望这个解释有帮助。如果您还有其他问题,请随时提出。

英文:
#include&lt;stdio.h&gt;
int main(){
  char names[3][5]={{&#39;a&#39;,&#39;b&#39;,&#39;c&#39;,&#39;d&#39;,&#39;\0&#39;},{&#39;e&#39;,&#39;f&#39;,&#39;g&#39;,&#39;h&#39;,&#39;\0&#39;},{&#39;k&#39;,&#39;l&#39;,&#39;m&#39;,&#39;n&#39;,&#39;\0&#39;}};
  char (*x)[5];

  for(x=names;x&lt;=x+2;x++){
    printf(&quot;%s\n&quot;,*x);
  }
}

the goals of this code is to printf the strings in this 2d array, but the output is really weird. It is the first time I see something like this.

ouptut:

&gt; 
&gt; abcd
&gt; efgh
&gt; klmn
&gt; �=3�
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; I8V
&gt; 
&gt; 
&gt; 3�
&gt; 
&gt; �
&gt; ��.m�
&gt; �
&gt; 
&gt; ?3�
&gt; 
&gt; zI8V
&gt; 
&gt; 
&gt; ��HU�yԁB��7x
&gt; �yԁB��7x
&gt; B��7x
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; �
&gt; 
&gt; ���
&gt; 
&gt; 
&gt; 
&gt; �yI8V
&gt; 
&gt; I8V
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; ��p��C�x86_64
&gt; �C�x86_64
&gt; x86_64
&gt; 4
&gt; 
&gt; 
&gt; /strcat
&gt; at
&gt; ELL=/bin/bash
&gt; bin/bash
&gt; ash
&gt; ESSION_MANAGER=local/kali:@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
&gt; N_MANAGER=local/kali:@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
&gt; AGER=local/kali:@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
&gt; local/kali:@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
&gt; /kali:@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
&gt; :@/tmp/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
&gt; p/.ICE-unix/836,unix/kali:/tmp/.ICE-unix/836
&gt; E-unix/836,unix/kali:/tmp/.ICE-unix/836
&gt; x/836,unix/kali:/tmp/.ICE-unix/836
&gt; ,unix/kali:/tmp/.ICE-unix/836
&gt; /kali:/tmp/.ICE-unix/836
&gt; :/tmp/.ICE-unix/836
&gt; /.ICE-unix/836
&gt; -unix/836
&gt; /836
&gt; WINDOWID=0
&gt; WID=0
&gt; 
&gt; CCESSIBILITY=1
&gt; IBILITY=1
&gt; TY=1
&gt; COLORTERM=truecolor
&gt; TERM=truecolor
&gt; truecolor
&gt; olor
&gt; XDG_CONFIG_DIRS=/etc/xdg
&gt; ONFIG_DIRS=/etc/xdg
&gt; _DIRS=/etc/xdg
&gt; =/etc/xdg
&gt; /xdg
&gt; XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0
&gt; ESSION_PATH=/org/freedesktop/DisplayManager/Session0
&gt; N_PATH=/org/freedesktop/DisplayManager/Session0
&gt; H=/org/freedesktop/DisplayManager/Session0
&gt; g/freedesktop/DisplayManager/Session0
&gt; edesktop/DisplayManager/Session0
&gt; top/DisplayManager/Session0
&gt; isplayManager/Session0
&gt; yManager/Session0
&gt; ger/Session0

Could you explain the meaning of that output and why am I getting it?

edit

Now I understand where I made the mistake, but anyway I want to know where does that output come.

答案1

得分: 1

The problem is that you compare the value of x to itself.
The expression x <= x + 2 can never be false.
The value of x is reevaluated for each occurrence in the expression, not just the left side.
You should store the result of x + 2 in a variable and use that variable on the right side of the expression.

英文:
#include &lt;stdio.h&gt;

int main(){
    char names[3][5] = {{&#39;a&#39;,&#39;b&#39;,&#39;c&#39;,&#39;d&#39;,&#39;\0&#39;},{&#39;e&#39;,&#39;f&#39;,&#39;g&#39;,&#39;h&#39;,&#39;\0&#39;},{&#39;k&#39;,&#39;l&#39;,&#39;m&#39;,&#39;n&#39;,&#39;\0&#39;}};
    char (*x)[5];

    //                   +- HERE
    //                   |
    for (x = names; x &lt;= x + 2; x++) {
        printf(&quot;%s\n&quot;, *x);
    }
}

The problem is that you compare the value of x to itself.
The expression x &lt;= x + 2 can never be false.
The value of x is reevaluated for each occurrence in the expression, not just the left side.
You should store the result of x + 2 in a variable and use that variable on the right side of the expression.

答案2

得分: 1

您好,以下是您要翻译的文本:

You wondered where those "weird strings" came from. They look like fragments of a typical Unix/Linux process environment, which consists of a list of name/value pairs known as environment variables.

Normally you access these strings in a C program by using the getenv function, but they are contained in an array of strings (similar to your program's arguments argv) copied into your process's address space when it is exec'ed. Under most Unix-like systems you can peek at the raw environment strings using code like the following:

#include <stdio.h>

int main(int argc, char **argv, char **envp)
{
    char *p;
    for(p = *envp;; p++) putchar(*p);
}

or

extern char **environ;

int main()
{
    char *p;
    for(p = *environ;; p++) putchar(*p);
}

Those are both quickly and crudely written, and sail off the end of the environment and eventually crash (as indeed your program did). A cleaner way of printing the environment would be:

char **v;
char *p;
for(v = environ; *v != NULL; v++) {
    for(p = *v; *p != '
char **v;
char *p;
for(v = environ; *v != NULL; v++) {
    for(p = *v; *p != '\0'; p++) putchar(*p);
    putchar('\n');
}
'
; p++) putchar(*p);
putchar('\n'); }
英文:

You wondered where those "weird strings" came from. They look like fragments of a typical Unix/Linux process environment, which consists of a list of name/value pairs known as environment variables.

Normally you access these strings in a C program by using the getenv function, but they are contained in an array of strings (similar to your program's arguments argv) copied in to your process's address space when it is exec'ed. Under most Unix-like systems you can peek at the raw environment strings using code like the following:

#include &lt;stdio.h&gt;

int main(int argc, char **argv, char **envp)
{
    char *p;
    for(p = *envp;; p++) putchar(*p);
}

or

extern char **environ;

int main()
{
    char *p;
    for(p = *environ;; p++) putchar(*p);
}

Those are both quickly and crudely written, and sail off the end of the environment and eventually crash (as indeed your program did). A cleaner way of printing the environment would be

char **v;
char *p;
for(v = environ; *v != NULL; v++) {
    for(p = *v; *p != &#39;
char **v;
char *p;
for(v = environ; *v != NULL; v++) {
for(p = *v; *p != &#39;\0&#39;; p++) putchar(*p);
putchar(&#39;\n&#39;);
}
&#39;; p++) putchar(*p); putchar(&#39;\n&#39;); }

huangapple
  • 本文由 发表于 2023年2月26日 22:59:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75572835.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定