【问题标题】:Why doesn't strcpy work?为什么 strcpy 不起作用?
【发布时间】:2014-06-18 14:19:25
【问题描述】:
    char sentence2[10];

    strncpy(sentence2, second, sizeof(sentence2));  //shouldn't I specify the sizeof(source) instead of sizeof(destination)?

    sentence2[10] = '\0';                       //Is this okay since strncpy does not provide the null character.

    puts(sentence2);
//////////////////////////////////////////////////////////////

    char *pointer = first;
    for(int i =0; i < 500; i++)                 //Why does it crashes without this meaningless loop?!
    {
        printf("%c", *pointer);
        if(*pointer == '\n')
            putchar('\n');
        pointer++;
    }

所以这就是问题所在。当我运行这段代码的第一部分时,程序崩溃了。 但是,当我添加只在内存位置打印垃圾值的 for 循环时,它不会崩溃,但仍然不会正确地 strcpy。

其次,当使用strncpy时,我不应该指定sizeof(source)而不是sizeof(destination),因为我正在移动源的字节吗?

第三,在 strncpy 之后添加空终止字符对我来说很有意义,因为我已经读过它不会自行添加空字符,但我收到警告说它可能越界从我的pelles c IDE存储。

第四个也是最重要的,为什么简单的 strcpy 不起作用?!?!

/////////////////////////////////////// /////////////////////////////////////////p>

更新:

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

void main3(void)
{
    puts("\n\n-----main3 reporting for duty!------\n");
    char *first = "Metal Gear";
    char *second = "Suikoden";
    printf("strcmp(first, first)  = %d\n", strcmp(first, first));   //returns 0 when both strings are identical.
    printf("strcmp(first, second) = %d\n", strcmp(first, second));  //returns a negative when the first differenet char is less in first string.  (M=77  S=83)
    printf("strcmp(second, first) = %d\n", strcmp(second, first));  //returns a positive when the first different char is greater in first string.(M=77  S=83)

    char sentence1[10]; 
    strcpy(sentence1, first);
    puts(sentence1);
    char sentence2[10];
    strncpy(sentence2, second, 10); //shouldn't I specify the sizeof(source) instead of sizeof(destination).
    sentence2[9] = '\0';                        //Is this okay since strncpy does not provide the null character.

    puts(sentence2);
    char *pointer = first;
    for(int i =0; i < 500; i++)                 //Why does it crashes without this nonsensical loop?!
    {
        printf("%c", *pointer);
        if(*pointer == '\n')
            putchar('\n');
        pointer++;
    }
}

这就是我自学编程的方式。我编写代码并评论我所知道的一切,以便 下次我需要查找某些内容时,我只需查看文件中自己的代码即可。在这一篇中,我正在尝试学习 c 中的字符串库。

【问题讨论】:

  • 很可能,sizeof 在这里完全不合适,无论是源大小还是目标大小。
  • 你能给一个complete, minimal example 而不仅仅是这个sn-p 吗?特别是,了解second 的样子会很有用。
  • sentence2[10] = '\0'; 超出范围,并导致未定义行为
  • 我尝试用目标字节大小(10 个字节)替换该部分,但仍然无法正常工作。我也尝试删除空字符分配,但没有任何改变。
  • @alvits 也尝试过 .. 没有任何改变。

标签: c strcpy


【解决方案1】:
char *first = "Metal Gear";
char sentence1[10]; 
strcpy(sentence1, first);

这不起作用,因为first 有 11 个字符:字符串中的十个字符,加上空终止符。所以你需要char sentence1[11]; 或更多。

strncpy(sentence2, second, sizeof(sentence2));  

//我不应该指定sizeof(source)而不是sizeof(destination)吗?

没有。 strncpy 的第三个参数应该是目标的大小。 strncpy 函数总是会写入那么多字节。

如果您想使用strncpy,您还必须放置一个空终止符(并且该终止符必须有足够的空间),除非您确定strlen(second) &lt; sizeof sentence2

一般来说,strncpy 几乎不是一个好主意。如果您想将一个以 null 结尾的字符串放入可能太小的缓冲区中,请使用 snprintf

这就是我自学编程的方式。

通过反复试验来学习 C 是不好的。问题是,如果你编写了糟糕的代码,你可能永远不会知道。它可能看起来有效,但稍后会失败。例如,取决于sentence1 之后的内存中的内容,您的strcpy 是否会踩到任何其他变量的脚趾。

从一本书中学习无疑是最好的主意。如果你没有其他的,K&R 2 是一个不错的起点。

如果您没有书,请务必查找在线文档以了解标准功能。您可以通过阅读他们的手册页或 C 标准草案中的定义等来了解有关 strcpystrncpy 的所有这些信息。

【讨论】:

  • +1 .. 我确实有 K&R,但那本书总是让我生气 :)。我知道它是最好的,如果不是最好的 C 书籍之一,但它期望太多。对于像我这样的新手来说,示例代码太难了。因此,正如您所建议的那样,我目前正在从在线文档中学习。感谢您花时间回答我的问题。
【解决方案2】:

这是一个数组边界写入错误。指数只有0-9

sentence2[10] = '\0';

应该是

sentence2[9] = '\0';

其次,您正在保护目标免受缓冲区溢出,因此指定其大小是适当的。

编辑:

最后,在这段非常糟糕的代码中,真的不值得一提,与strcpy()strncpy() 都不相关,但似乎让我赢得了@nonsensicke 的不喜欢,他似乎写得很冗长而深思熟虑的帖子......有以下几点:

char *pointer = first;
for(int i =0; i < 500; i++)
{
    printf("%c", *pointer);
    if(*pointer == '\n')
        putchar('\n');
    pointer++;
}

您在 for 循环中使用 int i=0 是 C99 特定的。根据您的编译器和编译器参数,它可能会导致编译错误。

for(int i =0; i < 500; i++)

更好

int i = 0;
...
for(i=0;i<500;i++)

您忽略检查printf的返回码或表示您故意忽略它。毕竟 I/O 可能会失败...

printf("%c", *pointer);

更好

int n = 0;
...
n = printf("%c", *pointer);
if(n!=1) { // error! }

(void) printf("%c", *pointer);

有些人会因为你没有在 if 语句中使用 {} 而指责你

if(*pointer == '\n') putchar('\n');

更好

if(*pointer == '\n') {
    putchar('\n');
}

但是等等还有更多...你没有检查putchar()的返回码... dang

更好

unsigned char c = 0x00;
...
if(*pointer == '\n') {
    c = putchar('\n');
    if(c!=*pointer) // error
}

最后,有了这个讨厌的小循环,你基本上就像在郁金香田里的猕猴桃一样在记忆中嬉戏,如果你打到换行符就很幸运。根据操作系统(如果您甚至有操作系统),您实际上可能会遇到某种类型的故障,例如在您的进程空间之外,可能在可寻址 RAM 之外等。提供的信息不足以说明实际情况,但它可能会发生。

除了对代码的其余部分进行某种类型的详细分析是荒谬的之外,我的建议是完全删除它。

干杯!

【讨论】:

  • 这并不是他的代码的全部错误。请同时解决其他问题...
  • @Mustafa,我完全同意循环并不重要,因此我最初没有解决它。我在编辑前的帖子中简洁地回答了最初的问题,并因我的麻烦而获得了反对票。虽然可能更直接一些,但不要看帖子的厚颜无耻,那里有一些花絮可以真正改善您的编程。干杯!
  • @nonsensickle,我几乎总是在第一个错误停止工作时停止。提出问题的人可以解决该问题,然后应该鼓励他们更仔细地查看其代码的其余部分并自己解决其他问题。 maha 的前四行给出了使用数组索引 >= 10 不好的附加信息,发帖者应该能够自己考虑到这一点。
  • @gasher729 我对这种哲学没有任何意见。事实上,我在一些答案中也做了同样的事情。我只要求你写一个脚注,解释这就是你正在做的事情,我很乐意投票。
  • @gnasher729 感谢您更新您的帖子,很抱歉直到现在才按承诺进行投票。 +1
【解决方案3】:

你的问题从这里开始:

char sentence1[10]; 
strcpy(sentence1, first);

first 中的字符数(不包括终止空字符)为10。为sentence1 分配的空间必须至少为11,程序才能以可预测的方式运行。由于您已经使用了不应该使用的内存,因此期望之后的任何行为都是不正确的。

你可以通过改变来解决这个问题

char sentence1[10]; 

char sentence1[N]; // where N > 10.

但是,你必须问问自己。您想通过在处于错误边缘的堆栈上分配内存来完成什么?您是否正在尝试了解事物在错误/正确边界上的行为方式?如果第二个问题的答案是肯定的,希望你能从中吸取教训。如果没有,我希望你学会了如何分配足够的内存。

【讨论】:

  • @R Sahu:+1 感谢修复它的人。我只分配 10 个字符的原因是我认为从 0 开始计数,有 11 个字符的空间。 sentence2 是 11,包括空字符。我不明白为什么第一个句子还不够。
猜你喜欢
  • 2017-11-21
  • 2016-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-24
  • 2010-11-18
  • 1970-01-01
相关资源
最近更新 更多