c-解决问题:将句子中的单词颠倒过来.AddressSanitizer:堆栈缓冲区溢出



im试图解决C语言中的一个问题,其中我们需要颠倒句子中的单词。例如";你好,我的名字叫"至";是我的名字"你好";。我面临的问题是堆栈溢出错误。不完全确定我的代码是否也能完美工作。如果知道我做错了什么,我会很感激的。非常感谢。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int my_strlen(char sentence[]) {
int count = 0;
for (int i = 0 ; sentence[i] != '' ; i++) {
count++;
}
return count;
}
void reverse_words(char sentence[]) {
int len = my_strlen(sentence);
int word_start = len;
int word_end = len;
int index = 0;
int i;
char reverse[len + 1];
while (word_start > 0) {
if (sentence[word_start] == ' ') {
i = word_start + 1;
while (i <= word_end) {
reverse[index] = sentence[i];
i++;
index++;
}
reverse[index++] = ' ';
word_end = word_start - 1;
}
word_start--;
}
for (int j = 0 ; j <= word_end ; j++) {
reverse[index] = sentence[j];
index++;
}
reverse[index] = '';
for (int j = 0 ; j < index ; j++) {
sentence[index] = reverse[index];
}
}
int main(void) {
char sentence[] = "abcd efgh ijkl mnop qrst uvxy z";
reverse_words(sentence);
for (int i = 0 ; i < sizeof(sentence) / sizeof(sentence[0]) - 1 ; i++) {
printf("%c", sentence[i]);
}
printf("n");
}

只需考虑传递的字符串仅包含一个单词的情况,例如"A"

在这种情况下,变量len将等于1

阵列reverse将只有两个元素

char reverse[len + 1];

现在在这个while循环

while (word_start > 0) {
if (sentence[word_start] == ' ') {
i = word_start + 1;
while (i <= word_end) {
reverse[index] = sentence[i];
i++;
index++;
}
reverse[index++] = ' ';
word_end = word_start - 1;
}
word_start--;
}

if语句的主体将不会获得控件,因为该字符串不包含空格。所以实际上while循环看起来像

while (word_start > 0) {
//...
word_start--;
}

因此,在循环之后word_start将变为等于0

由于以下原因,环路

for (int j = 0 ; j <= word_end ; j++) {
reverse[index] = sentence[j];
index++;
}

你会有reverse[0] = 'A'reverse[1] = '',然后在这个声明之后

reverse[index] = '';

您将获得reverse[2] = ''。也就是说,有人试图在数组之外进行写入。

此外,这个for循环通常使用变量word_end的无效值,因为该变量可以在前面的while循环中减少。

另一个问题是while循环中的条件

while (i <= word_end) {

在循环的第一次迭代中,可以在结果字符串的中间插入终止零字符''

注意字符串可以包含相邻的空格。在这种情况下,您的方法将是不正确的。

通常,这样的任务是通过以下方式实现的。

首先你需要反转整个字符串,然后从字符串的开头开始反转字符串中的每个单词。不需要使用辅助阵列。使用辅助可变长度数组会使函数不安全。

这里有一个演示程序,其中的函数不使用标准的C字符串函数。

#include <stdio.h>
size_t my_strlen( const char *s ) 
{
const char *p = s;
while ( *p ) ++p;
return p - s;
}
void reverse_n( char *s, size_t n )
{
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n-i-1];
s[n-i-1] = c;
}
}
char * reverse_words( char *s ) 
{
size_t n = my_strlen( s );
reverse_n( s, n );

for ( char *p = s; *p; )
{
while ( *p == ' ' || *p == 't' ) ++p;
if ( *p )
{
char *q = p;
while ( *++p && *p != ' ' && *p != 't' );
reverse_n( q, p - q );
}
}
return s;
}
int main( void ) 
{
char sentence[] = "hello my name is";
puts( sentence );
puts( reverse_words( sentence ) );
}

程序输出为

hello my name is
is name my hello

正如您所看到的,函数reverse_words不使用辅助可变长度数组。

以下是其中一个原始函数的代码,有三个高度可见的注释,包括两个更改:

void reverse_words(char sentence[]) {
int len = my_strlen(sentence);
int word_start = len;
int word_end = len;
int index = 0;
int i;
char reverse[len + 1];
while (word_start > 0) {
if (sentence[word_start] == ' ') {
i = word_start + 1;
while (i <= word_end) {
reverse[index] = sentence[i];
i++;
index++;
}
reverse[index++] = ' '; //  *** Comment #1 below ***
word_end = word_start - 1;
}
word_start--;
}
#if 0 // Comment #2 below
for (int j = 0 ; j <= word_end ; j++) {
#else
for (int j = 0 ; j < word_end ; j++) {
#endif
reverse[index] = sentence[j];
index++;
}
reverse[index] = '';
for (j = 0 ; j < index ; j++) {
#if 0 // Comment #3 below
sentence[index] = reverse[index];
#else
sentence[j] = reverse[j]; 
#endif
}
}

#1-将先前不存在的空间添加到第一个"0"的末尾;单词";copy
#2-修剪最后一个"后面的空间的副本;单词";复制修复了溢出
#3-这永远不会起作用。固定的


固定#3(根据需要(导致另一个观察结果
在处理索引时,在中途代码使用word_end作为单词的最后字符的索引。但是,最初,word_end索引+1。3号修正后,一个非常简单的修正是:

int len = my_strlen(sentence);
int word_start = len;
int word_end = len - 1; // index of last character of last "word"

使代码的其余部分保持原样。

Off by one errors是常见的错误原因。

相关内容

  • 没有找到相关文章

最新更新