变量为什么突然变成0?(C语言)

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

why does the variable become 0 suddenly?(c language)

问题

我练习基本的编程,所以我编写了一段代码来询问用户的姓名,然后我想逐个字符打印用户的姓名,接着打印整个姓名和姓名的长度,最后打印用户姓名中的偶数位置字符,如第2个、第4个等等。

我遇到了两个问题,首先是保存姓名长度的变量在最后一个循环中变成了零。我的第二个问题是偶数位置的字符中也包括了奇数位置的字符。

我输入了用户名:james
我期望的输出是:

j
5
a
5
m
5
e
5
s
5
hello james,你的名字有5个字符
ae

以下是您提供的代码,我已经对其中的中文注释进行了翻译:

#include <stdio.h>
#include <cs50.h>
#include <string.h>

int main(void)
{
    string name = get_string("请输入你的名字:");
    int x = strlen(name);
    char new[4] = ""; // 用于存储偶数位置字符的数组,应该增加大小
    for (int i = 0; i < x; i++)
    {
        printf("%c\n", name[i]);
        if ((i + 1) % 2 == 0)
        {
            strcat(new, &name[i]);
        }
        printf("%i\n", x); // 这里应该打印字符的位置 i+1
    }

    printf("你好%s,你的名字有%i个字符\n", name, x);
    printf("%s\n", new);
}
请输入你的名字:james
j
5
a
0
你好james,你的名字有0个字符
ames

请注意,上述代码中有一些问题,您可能需要修复这些问题以获得预期的输出。

英文:

i was practicing basic so i write a code to ask about user name and then i wanted to print user name character by character , then the whole name and the length of it and at the end the even numbers characters of the user name like the 2nd,4th and so on
i got two problems first the variable holding name length become zero at the last for cycle
my second problem was the even characters as i get odd ones too

i entered the user name : james
i expected the out put to be :

j
5
a 
5
m
5
e
5
s
5
hello james , your name has 5 characters
ae
#include &lt;stdio.h&gt;
#include &lt;cs50.h&gt;
#include &lt;string.h&gt;

int main(void)
{
    string name = get_string(&quot;whats your name ? &quot;);
    int x = strlen(name);
    char new[4] = &quot;&quot;;
    for (int i = 0 ; i &lt; x ; i++)
    {
        printf(&quot;%c\n&quot; ,name[i] );
        if ( (i+1) % 2  == 0)
        {
            strcat(new,&amp;name[i]);
        }
            printf(&quot;%i\n&quot;,x);
    }

    printf(&quot;hello %s ,your name has %i characters \n&quot;, name,x);
    printf(&quot;%s\n&quot;,new);
}
whats your name ? james
j
5
a
0
hello james ,your name is 0 characters long
ames

答案1

得分: 1

主要问题是new缓冲区不足以容纳您要写入其中的数据。我怀疑主要混淆在于strcat的不正确使用。当您写strcat(new,&amp;name[i]);时,它不会将单个字符复制到new的末尾。如果name是“james”而i为2,则&amp;name[i]是“m”的地址,而strcat尝试将字符串“mes”复制到new的末尾。如果您只想复制单个字符,strcat不是正确的工具。在我看来,string typedef的使用加剧了这种混淆,它的唯一目的是混淆学生。停止使用string,而改用char *。如果您希望真正理解C,您必须理解这个细节。

如果您想遍历字符串并将每隔一个字符复制到数组中,也许您想要类似下面的代码。请注意,如果使用未知输入,您必须检查数组边界。

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char *name = argc > 1 ? argv[1] : "james";
    int length = strlen(name);
    char new[128] = "";
    char *d = new;

    for (int i = 1; i < length && i < sizeof new - 1; i += 2) {
        *d++ = name[i];
    }
    *d = '
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char *name = argc > 1 ? argv[1] : "james";
    int length = strlen(name);
    char new[128] = "";
    char *d = new;

    for (int i = 1; i < length && i < sizeof new - 1; i += 2) {
        *d++ = name[i];
    }
    *d = '\0';

    printf("hello %s, your name has %i characters \n", name, length);
    printf("%s\n", new);

    return 0;
}
'
;
printf("hello %s, your name has %i characters \n", name, length); printf("%s\n", new); return 0; }

许多人认为将循环编写为以下方式更为自然:

char *end = new + min(length, sizeof new);
for (name += 1; d < end; name += 2) {
    *d++ = *name;
}

并且摆脱所有的索引。请注意,这需要一个min的定义来计算最小值,并且它失去了原始name的开始位置,因此您需要跟踪名称的起始位置或使用不同的变量来进行循环。与索引不同,您只需跟踪三个指针:一个指向要复制的字符,一个指向要复制到的目标以及一个指向目标缓冲区的末尾,以防止超出它。

英文:

The main issue is that the new buffer is not large enough to hold the data you are writing to it. I suspect the primary confusion is the incorrect usage of strcat. When you write strcat(new,&amp;name[i]);, it does not copy a single character to the end of new. If name is "james" and i is 2, then &amp;name[i] is the address of the 'm' and strcat attempts to copy the string "mes" to the end of new. If you just want to copy a single character, strcat is the wrong tool. IMO, this confusion is exacerbated by the use of the string typedef, whose only purpose is to confuse students. Stop using string and use char * instead. You must understand this detail if you are ever to understand C.

If you want to iterate through the string and copy every other character into an array, perhaps you want something like below. Note that you must check the array bounds if you are using unknown input.

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

int
main(int argc, char **argv)
{
	char *name = argc &gt; 1 ? argv[1] : &quot;james&quot;;
	int length = strlen(name);
	char new[128] = &quot;&quot;;
	char *d = new;
	/*
	Checking the parity of i inside the loop is a code smell, but
	we leave this as dead code for comparison to the original.  Simply
	skipping the unwanted indices is done below the dead code.
	for( int i = 0; i &lt; length &amp;&amp; i &lt; sizeof new - 1; i += 1 ){
		if( (i+1) % 2 == 0 ){
			*d++ = name[i];
		}
	}
	*/
	for( int i = 1; i &lt; length &amp;&amp; i &lt; sizeof new - 1; i += 2 ){
		*d++ = name[i];
	}
	*d = &#39;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
int
main(int argc, char **argv)
{
char *name = argc &gt; 1 ? argv[1] : &quot;james&quot;;
int length = strlen(name);
char new[128] = &quot;&quot;;
char *d = new;
/*
Checking the parity of i inside the loop is a code smell, but
we leave this as dead code for comparison to the original.  Simply
skipping the unwanted indices is done below the dead code.
for( int i = 0; i &lt; length &amp;&amp; i &lt; sizeof new - 1; i += 1 ){
if( (i+1) % 2 == 0 ){
*d++ = name[i];
}
}
*/
for( int i = 1; i &lt; length &amp;&amp; i &lt; sizeof new - 1; i += 2 ){
*d++ = name[i];
}
*d = &#39;\0&#39;;
printf(&quot;hello %s, your name has %i characters \n&quot;, name, length);
printf(&quot;%s\n&quot;, new);
return 0;
}
&#39;; printf(&quot;hello %s, your name has %i characters \n&quot;, name, length); printf(&quot;%s\n&quot;, new); return 0; }

Many would think it more natural to write the loop as something like:

char *end = new + min(length, sizeof new);
for( name += 1; d &lt; end; name += 2 ){                                      
        *d++ = *name;                                                      
} 

and get rid of all of the indexing. Note, this requires a definition of min to compute the minimum, and it loses track of the beginning of the original name, so you would need to keep track of the start of the name or use a different variable for the loop. Instead of indexing, you just keep track of three pointers; one to the character you want to copy, one to the destination to which you want to copy it, and one to the end of the destination buffer so you don't go past it.

答案2

得分: 0

以下是翻译好的部分:

"Your entered a string &quot;james&quot; that contains 6 characters including the terminating zero character &#39;\0&#39;."
你输入了一个字符串 &quot;james&quot;,它包含了6个字符,包括终止零字符 &#39;\0&#39;

"And you declared a character array that has only 4 elements."
而且你声明了一个只有 4 个元素的字符数组。

"In this if statement"
在这个if语句中

"when for example i is equal to 1 the string pointed to by the pointer expression name + 1 is appended to the character array new."
例如,当 i 等于 1 时,由指针表达式 name + 1 指向的字符串被追加到字符数组 new 中。

"This is the following string (represented as a character array) { &#39;a&#39;, &#39;m&#39;, &#39;e&#39;, &#39;s&#39;, &#39;\0&#39; }. As it is seen the string contains 5 characters including the terminating zero character &#39;\0&#39;."
这是下面的字符串(表示为字符数组){ &#39;a&#39;, &#39;m&#39;, &#39;e&#39;, &#39;s&#39;, &#39;\0&#39; }。如你所见,该字符串包含了包括终止零字符 &#39;\0&#39; 在内的 5 个字符。

"As a result this call of strcat results in overwriting memory outside the array new that invokes undefined behavior."
因此,这次对 strcat 的调用导致了在数组 new 外部覆盖内存,从而引发了未定义的行为。

"There is no need to use the function strcat because instead of storing only one character in the array new the function tries to append a whole substring."
没有必要使用函数 strcat,因为该函数尝试追加一个完整的子串,而不是仅存储一个字符在数组 new 中。

"You could write for example"
例如,你可以这样写

"Pay attention to that the array new will contain a string because all its elements were initially initialized by zeroes in the array declaration"
请注意,数组 new 将包含一个字符串,因为在数组声明中所有元素都被初始为零。

"On the other hand, using the magic number 4 in the array declaration is unsafe. Instead you could declare for example a variable length array like"
另一方面,在数组声明中使用魔数 4 是不安全的。相反,你可以声明一个可变长度的数组,如下所示

"In this case your program will work even if the user will enter a more long name."
在这种情况下,即使用户输入更长的名称,你的程序也会正常工作。

英文:

Your entered a string &quot;james&quot; that contains 6 characters including the terminating zero character &#39;\0&#39;.

whats your name ? james

And you declared a character array that has only 4 elements.

char new[4] = &quot;&quot;;

In this if statement

    if ( (i+1) % 2  == 0)
    {
        strcat(new,&amp;name[i]);
    }

when for example i is equal to 1 the string pointed to by the pointer expression name + 1 is appended to the character array new.

        strcat(new,&amp;name[i]);

This is the following string (represented as a character array) { &#39;a&#39;, &#39;m&#39;, &#39;e&#39;, &#39;s&#39;, &#39;\0&#39; }. As it is seen the string contains 5 characters including the terminating zero character &#39;\0&#39;. As a result this call of strcat results in overwritting memory outside the array new that invokes undefined behavior.

There is no need to use the function strcat because instead of storing only one character in the array new the function tries to append a whole substring.

You could write for example

for (int i = 0 ; i &lt; x ; i++)
{
    printf(&quot;%c\n&quot; ,name[i] );
    if ( (i+1) % 2  == 0)
    {
        new[i / 2] = name[i];
    }
        printf(&quot;%i\n&quot;,x);
}

Pay attention to that the array new will contain a string because all its elements were initially initialized by zeroes in the array declaration

char new[4] = &quot;&quot;;

On the other hand, using the magic number 4 in the array declaration is unsafe. Instead you could declare for example a variable length array like

int x = strlen(name);
char new[x / 2 + 1];
memset( new, 0, x / 2 + 1 );

In this case your program will work even if the user will enter a more long name.

huangapple
  • 本文由 发表于 2023年7月23日 19:54:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76748089.html
匿名

发表评论

匿名网友

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

确定