malloc中的反向字符串

时间:2016-02-01 07:20:22

标签: c string malloc strcpy strcat

我需要在这个问题中定义一个“单词”,它是任何不包含空格或空字符的字符序列。 例如,字符串“Hello World”将包含2个单词。但是,一个单词实际上可能是空的 即零个字符。 句子是一系列由1个空格字符分隔的单词。所以“Hello World”将是一个 两个字的句子。 ReverseSentence的目标是用单词来反转句子。 现在,我有一个错误,程序继续调用函数并打印出a1到a5。达到a5后,似乎程序中止和核心倾倒。如果我用空格替换空白,它将读取前一个输入并根据空格数替换。 我哪里错了?

ReverseSentence.c

#include <stdlib.h>  /* malloc */
#include <string.h>  /* strcat, strcpy */

void ReverseSentence(char *str)
{
    char *newSentence;
    int i, j, start, len;
    /* contains the string length of the input */
    len = strlen(str);
    /* position or index in the array */
    start = strlen(str);
    /* malloc */
    newSentence = malloc(len + 1);

    /* loop checks from the right of the sentences */
    for (i = len; i >= 0; i--) {
        /* if index reach the array with a space or zero */
        if (str[i] == ' ' || i == 0) {
            /* allocates memory */
            char *word = malloc((start - i) + 1);
            int c = 0;

            if (i == 0) 
                /* index remains same */
                j = i;
            else
                j = i + 1;

            /* j smaller or equal than the start position */
            for (; j <= start; j++) {
                /*do a incremental*/
                word[c++] = str[j];
            }
            /* hits a null char */
            word[c] = '\0';
            /* string concatenate */
            strcat(newSentence, word);
            /* if index hits a space */
            if (str[i] == ' ')
                strcat(newSentence, " "); /* concatenate space to newSentence */
            else
                strcat(newSentence, "\0");
            start = i - 1;

            /* free memory */
            free(word);
        }
    }
    newSentence[len] = '\0';
    /* string copy */
    /* str is destination, newSentence is the source */
    /* copy new string to original string */
    strcpy(str, newSentence);
    /* free memory */
    free(newSentence);
}

的main.c

#include <stdio.h>
#include "ReverseSentence.h"

int main()
{
    char a1[] = "Hello World ";
    char a2[] = "abcdefghi ";
    char a3[] = " ";
    char a4[] = "C programming is a dangerous activity";
    char a5[] = "a "; /* a sentence with only empty words */
    ReverseSentence(a1);

    printf("Test case 1:\"%s\"\n", a1); /* prints "World Hello" */
    ReverseSentence(a2);

    printf("Test case 2:\"%s\"\n", a2); /* prints "abcdefghi" */
    ReverseSentence(a3);

    printf("Test case 3:\"%s\"\n", a3); /* prints "" */

    ReverseSentence(a4);
    printf("Test case 4:\"%s\"\n", a4); /* prints "activity dangerous a is pro Cgramming" */

    ReverseSentence(a5);
    printf("Test case 5:\"%s\"\n", a5); /* prints " " */

    return 0;
}

编辑:新版本

void ReverseSentence(char *str)
{
    /* holder */
    /* pointer to char */
    char *newSentence;
    int i, start, len, lastindex, size;

    /* contains the string length of the input */
    len = strlen(str);
    lastindex = strlen(str);
    /* starting position */
    start = 0;
    i = 0;
    /* malloc */
    newSentence = malloc(sizeof(char) * strlen(str));

    while (i >= 0) {
        for (i = len - 1; str[i] != '\0' && str[i] != ' '; i--) {
            lastindex--;
        }

        /* number of chars in string size */
        size = len - lastindex;
        /* Copy word into newStr at startMarker */
        strncpy(&newSentence[start], &str[lastindex], size);

        /* pointer move to right */
        start = start + size;
        /* Space placed into memory slot */
        newSentence[start] = ' ';
        /* start position moves by 1 towards the right */
        start = start + 1;
        /* pointer at len moves to left */
        lastindex = lastindex - 1;
        /* lastindex moves to where len is */
        len = lastindex;
    }

    /* Copy new string into old string */
    for (i = 0; str[i] != '\0'; i++) {
        str[i] = newSentence[i];
    }

    /* free memory */
    free(newSentence);
}

4 个答案:

答案 0 :(得分:2)

您的代码不安全。您永远不会初始化newSentence,因为malloc()仅分配但不初始化内存(与calloc()相反)。因此,您将从垃圾句子开始,在其中添加新内容(strcat())。根据垃圾的不同,即使在分配的内存中也可能没有0,并且您可以访问一些未分配的内存区域。

答案 1 :(得分:2)

除了马蒂亚斯的回答:你没有分配足够的内存,我只是做了一个疯狂的猜测,并在传递给malloc的参数中加了1。

newSentence = malloc(len + 2);   // +2 instead of +1

char *word = malloc((start - i) + 2);  // +2 instead of +1

现在它不再崩溃了。所以这里肯定有缓冲区溢出。

我现在不假装该程序是完全正确的。你应该看看这个。

答案 2 :(得分:1)

你的方法太复杂了。它有几个问题:

  • 您没有初始化newSentence:由于malloc内存未初始化,因此当您使用strcat复制其末尾的单词时,将调用未定义的行为。您可以使用*newSentence = '\0';

  • 解决此问题
  • 当您将单词复制到已分配的word缓冲区时,您会迭代并包含start,然后在末尾添加'\0'。你有效地为最后一个字写了一个字节太多(case i == 0)。这会调用未定义的行为。

  • strcat(newSentence, "\0");什么都不做。

  • 为找到的每个单词分配缓冲区非常浪费,您只需使用memcpy或简单的for循环复制该单词。

您可以通过以下步骤进行简化:

  • 分配缓冲区并将字符串复制到其中。
  • 对于字符串中的每个单词,将其复制到目标的末尾,如果不在结尾,则复制分隔符。
  • 释放缓冲区。

以下是代码:

char *ReverseSentence(char *str) {
    int len = strlen(tmp);    /* length of the string */
    char *tmp = strdup(str);  /* copy of the string */
    int i;        /* index into the copy */
    int j = len;  /* index into the string */
    int n;        /* length of a word */
    for (i = 0; i < len; ) {
        n = strcspn(tmp + i, " ");   /* n is the length of the word */
        j -= n;                      /* adjust destination offset */
        memcpy(str + j, tmp + i, n); /* copy the word */
        i += n;                      /* skip the word */
        if (tmp[i] != '\0') {        /* unless we are at the end */
            j--;
            str[j] = tmp[i];         /* copy the separator */
            i++;
        }
    }
    free(tmp);                       /* free the copy */
    return str;
}

答案 3 :(得分:0)

新版程序中至少存在两个问题:

  • 您没有分配足够的内存,因此您不会考虑零终结符。你应该再分配一个字节。

  • 在您的第一个for循环中,您允许i变为-1。当i为零时,循环应该停止:修改for语句,如下所示:for(i=len-1; tr[i] != ' ' && i >= 0; i--)。你不正确地假设str缓冲区之前的第一个字节为零,因此str[i]!='\0'是错误的。 BTW在str缓冲区之前访问一个字节会产生未定义的行为。

  • 可能存在其他问题。