为什么这个简单的代码有时不提供工作????然后当我重新启动我的代码块时,它确实有效

时间:2014-04-19 22:28:26

标签: c

#include <stdio.h>
#include <stdlib.h>
main()
{
    char *a,*b,*c={0};
    int i=0,j=0;
    a=(char *)malloc(20*sizeof(char));
    b=(char *)malloc(20*sizeof(char));
    c=(char *)malloc(20*sizeof(char));
    printf("Enter two strings:");
    gets(a);
    gets(b);
    while(a[i]!=NULL)
    {
        c[i]=a[i];
        i++;
    }
     while(b[j]!=NULL)
     {
        c[i]=b[j];
        i++;
        j++;
     }
     printf("The concated string is %s",c);

     }

这很疯狂........我花了一整晚它没有工作,然后第二天晚上它突然完美......我很困惑

3 个答案:

答案 0 :(得分:4)

您的代码有很多问题。 如果你关心的只是使代码工作,并非所有这些都很重要。 但是,我在这里尝试向您展示代码中明确的不同误解,并向您展示如何更好地编写代码。

你误解了NULL意味着什么。 NULL指针不指向任何东西 字符串以&#39; \ 0&#39;终止。这是一个ASCII NUL,不是一回事,尽管它们都使用值0。

char * s =&#34;你好&#34 ;;

上面的字符串实际上是6个字符长。你好5个字节,1个用于&#39; \ 0&#39;那个被困在最后。顺便说一句,这意味着您只能拥有长达19个字符的字符串,因为您需要为终端保留一个字节&#39; \ 0&#39;

char * r = NULL;

指针r指向任何东西。没有&#39; \ 0&#39;在那里,如果你试图看r [0],你会崩溃。

正如奥加指出的那样,你错过了终止与&#39; \ 0&#39;这会产生随机错误,因为你的printf将继续尝试打印,直到找到它的第一个零字节。你是否在任何特定的运行中崩溃都是运气问题。零是常见的,所以通常你会在崩溃之前停止,但你可能会在字符串后打印出一些垃圾。

就个人而言,我宁愿崩溃,也不会让程序随机打印出错误的东西。至少在你崩溃的时候,你知道出了什么问题,可以解决它。

你似乎也忘记释放你对malloc的记忆。 如果您打算使用malloc,最后应该免费使用:

int* a = malloc(20);
...
free(a);

你也只是在拍摄20个字符。如果你重复一遍,你会在记忆中做出可怕的事情。 20似乎太短,你只有19个字符加上结尾的空格来玩,但是如果你在a和b中分别有20个字符,你需要在c中有40个字符。

如果这是使用malloc的赋值,那么使用它,但是当你完成时你应该自由。如果你不必使用malloc,这个例子没有显示使用它的原因,因为你正在分配一小块恒定的内存。

您正在初始化c:

char* c = {0};

以一种毫无意义的方式。 {0}是一个具有单个零值的数组。 c指向它,但是你立刻将它指向别的东西,再也不会看你的小阵列了。

你可能意味着C首先指向的是什么。 那将是:

char* c = NULL;

然后你立即消灭了null,那么为什么要初始化c,而不是a和b?

作为一般规则,您不应声明值并在以后初始化它们。你总是可以做一些愚蠢的事情,并在初始化之前使用它们。相反,在声明:

时进行初始化
int* a = malloc(20);
int* b = malloc(20);
int* c = malloc(40);

顺便提一下,char的大小按定义1,所以: 20 * sizeof(char) 与20相同。

你可能看到了一个例子:

20 * sizeof(int)

因为sizeof(int)不是上面的1所做的事情。通常sizeof(int)是4个字节,因此上面将分配80个字节。

获取是不安全的,因为它没有说缓冲区有多长 总是使用fgets而不是获取。 (见下文)。 许多计算机都使用此错误进行攻击(请参阅http://en.wikipedia.org/wiki/Robert_Tappan_Morris

但是,由于不需要malloc,在你的代码中,你真的应该写:

enum { SIZE = 128 };
char a[SIZE];
fgets(a, SIZE, STDIN);
char b[SIZE];
fgets(b, SIZE, STDIN);
char c[SIZE*2];
int i;
int j = 0;
for (i = 0; a[i] != '\0' && i < 127; i++)
  c[j++] = a[i];
for (i; b[i] != '\0' && i < 127; i++)
  c[j++] = a[i];
c[j] = '\0';

...

最后,我不知道你是在学习C还是C ++。我将简单地指出,在C ++中,这种编程很容易,其中很多工作都是为您完成的。你可以先用简单的方法完成连接,然后学习更难的所有指针操作。

#include <string>
#include <iostream>
using namespace std;
int main() {
  string a,b,c;
  getline(cin, a); // read in a line
  getline(cin, b);
  c = a + b;
  cout << c;
}

当然,你仍然需要学习这个低级指针,才能成为C ++中一个复杂的程序员,但如果只是为了读入和连接行,C ++会让它变得更容易。

答案 1 :(得分:2)

您未正确终止c。在printf

之前添加此内容
c[i] = '\0';

如果i处的字符恰好是0,则省略空终止似乎会正常工作,但您需要将其设置为确定。

答案 2 :(得分:0)

字符串c没有以null char终止,这意味着printf不知道停止的位置,并且当程序超出时可能会对程序进行段错误。你可能获得零星成功的原因是,当你分配它时,malloced区域有一个随机的机会被预先归零,如果是这样的话,它会成功,因为一个空字符表示为一个字面的0字节。

这里有两种解决方案,首先你可以手动终止带有空字符串的字符串,如下所示:

c[i] = '\0';

其次,您可以使用calloc而不是malloc,它可以保证内存始终预先归零。

作为附注,您应该在代码中添加一些长度检查,以确保如果A和B都超过10,则c不会溢出。(或者只是使c 40长)

我希望这会有所帮助。