我需要在这个问题中定义一个"单词",作为不包含空格或空字符的任何字符序列。例如,字符串“Hello World”
将包含 2 个单词。但是,实际上单词可以为空即零字符。句子将是一系列由 1 个空格字符分隔的单词。所以“Hello World”
将是一个两个字的句子。ReverseSentence
的目标是从单词上颠倒句子。现在,我遇到了一个错误,程序继续调用函数并打印出 a1 到 a5。到达 a5 后,程序似乎中止并且核心被转储。如果我用空格替换空白,它将读取上一个输入并根据空格数替换。我哪里出错了?
反向句子.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] = ' ';
/* string concatenate */
strcat(newSentence, word);
/* if index hits a space */
if (str[i] == ' ')
strcat(newSentence, " "); /* concatenate space to newSentence */
else
strcat(newSentence, " ");
start = i - 1;
/* free memory */
free(word);
}
}
newSentence[len] = ' ';
/* string copy */
/* str is destination, newSentence is the source */
/* copy new string to original string */
strcpy(str, newSentence);
/* free memory */
free(newSentence);
}
主.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] != ' ' && 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] != ' '; i++) {
str[i] = newSentence[i];
}
/* free memory */
free(newSentence);
}
除了马蒂亚斯的回答:你没有分配足够的内存,我只是做了一个疯狂的猜测,并在传递给malloc
的参数中添加了 1。
newSentence = malloc(len + 2); // +2 instead of +1
和
char *word = malloc((start - i) + 2); // +2 instead of +1
现在它不再崩溃了。所以这里肯定有缓冲区溢出。
我不假装程序现在完全正确。你应该看看这个。
你的代码不安全。你永远不会初始化newSentence
,因为malloc()
只分配但不初始化内存(与calloc()
相反(。因此,您从一个垃圾句子开始,在其中附加一些新的东西(strcat()
(。根据垃圾的不同,即使在分配的内存中也可能没有 0,并且您访问一些未分配的内存区域。
你的方法太复杂了。它有几个问题:
-
您不初始化
newSentence
:由于内存未初始化malloc
因此当您复制末尾的单词时,您会调用未定义的行为strcat
.你可以用*newSentence = ' ';
来解决这个问题 -
将单词复制到分配的
word
缓冲区时,将迭代并包括start
,然后在末尾添加一个' '
。 你有效地写了一个字节,最后一个字太多了(案例i == 0
(。 这将调用未定义的行为。 -
strcat(newSentence, " ");
什么都不做。 -
为每个找到的单词分配缓冲区是浪费,您可以使用
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] != ' ') { /* unless we are at the end */
j--;
str[j] = tmp[i]; /* copy the separator */
i++;
}
}
free(tmp); /* free the copy */
return str;
}
中至少存在两个问题:
您没有分配足够的内存,也没有考虑零终止符。您应该再分配一个字节。
在第一个
for
循环中,你允许i
变为 -1。当i
为零时,循环应该停止:像这样修改你的for
语句:for(i=len-1; tr[i] != ' ' && i >= 0; i--)
。您错误地假设str
缓冲区之前的第一个字节为零,因此str[i]!=' '
是错误的。顺便说一句,在str
缓冲区之前访问一个字节会产生未定义的行为。可能还有其他问题。