C语言 Valgrind条件跳转或移动取决于未初始化的值-所有变量已初始化

zi8p0yeb  于 2023-05-28  发布在  其他
关注(0)|答案(1)|浏览(161)

Valgrind条件跳转或移动取决于未初始化的值
我有一个从动态分配的字符串中删除多余空格的函数,它工作正常,但我得到了一个关于未初始化变量的valgrind错误,我似乎无法确定它来自哪里。我已经初始化了所有变量,但这并不能解决错误。
下面是我的代码

#include "main.h"

void normalize_wspace2(char *_str);

int main(void)
{
    char s[] = " ls       -la f1\t folder2 this one\t\t    ";

    printf("s initial = %s,\n", s);
    normalize_wspace2(s);
    printf("s normalized = %s,\n", s);
}
void normalize_wspace2(char *_str)
{
    size_t i = 0, j = 0;

    for (i = 0, j = 0; _str[i] != '\0'; j++, i++)
    {
        if (_str[i] == ' ' || _str[i] == '\t' || _str[i] == '\v')
        {/* if whitespace is matched */
            if (i != 0)
            {/*only copy a single ' ' to normalized string*/
                _str[j] = ' ';
                i++;
                j++;
            }
            while (_str[i] == ' ' || _str[i] == '\t' || _str[i] == '\v')
            {/* loop through and ignore all other spaces*/
                i++;
            }
        }
        _str[j] = _str[i]; /*copy non-whitespace char to normalized string */
    }
    _str[j] = '\0';
    del_twspace(_str);
}

void del_twspace(char *s)
{
    size_t i = 0;
    int last_char = -1;

    if (s == NULL)
    {
        perror("error: del_twspace passed null\n");
        return;
    }
    while (s[i] != '\0')
    {/* find the last char, ignoring any whitespace */
        if (s[i] != ' ' && s[i] != '\t' && s[i] != '\n')
            last_char = i;
        i++;
    }
    
    s[last_char + 1] = '\0'; /* set char after last char to null */
}

Valgrind输出

$ valgrind -s --leak-check=full --show-leak-kinds=all --track-origins=yes ./a.out

==8876== Memcheck, a memory error detector
==8876== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8876== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==8876== Command: ./a.out
==8876== 
==8876== Conditional jump or move depends on uninitialised value(s)
==8876==    at 0x109323: normalize_wspace2 (in /workspaces/103507869/functions/cln/a.out)
==8876==    by 0x1091F4: main (in /workspaces/103507869/functions/cln/a.out)
==8876==  Uninitialised value was created by a stack allocation
==8876==    at 0x109169: main (in /workspaces/103507869/functions/cln/a.out)
==8876== 
s initial =  ls       -la f1     folder2 this one           ,
s normalized = ls -la f1 folder2 this one ,
==8876== 
==8876== HEAP SUMMARY:
==8876==     in use at exit: 0 bytes in 0 blocks
==8876==   total heap usage: 1 allocs, 1 frees, 4,096 bytes allocated
==8876== 
==8876== All heap blocks were freed -- no leaks are possible
==8876== 
==8876== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==8876== 
==8876== 1 errors in context 1 of 1:
==8876== Conditional jump or move depends on uninitialised value(s)
==8876==    at 0x109323: normalize_wspace2 (in /workspaces/103507869/functions/cln/a.out)
==8876==    by 0x1091F4: main (in /workspaces/103507869/functions/cln/a.out)
==8876==  Uninitialised value was created by a stack allocation
==8876==    at 0x109169: main (in /workspaces/103507869/functions/cln/a.out)
==8876== 
==8876== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
ffx8fchx

ffx8fchx1#

尾随空格出现问题:在这个循环之后

while (_str[i] == ' ' || _str[i] == '\t' || _str[i] == '\v')
        {/* loop through and ignore all other spaces*/
            i++;
        }

i将已经是_str中尾部'\0'的索引。然后它再次递增for(),因此下一次检查_str[i] != \0'已经超出_str的边界。
做解决它你可以只添加

if (_str[i] == '\0' ) {
            _str[j] = '\0';
            break;
        }

while循环之后,或者将循环体更改为

if (_str[i] == ' ' || _str[i] == '\t' || _str[i] == '\v')
    {/* if whitespace is matched */
        if (i != 0)
        {/*only copy a single ' ' to normalized string*/
            _str[j] = ' ';
             j++;
       }
        while (_str[i+1] == ' ' || _str[i+1] == '\t' || _str[i+1] == '\v')
        {/* loop through and ignore all other spaces*/
            i++;
        }
    } else {
        _str[j] = _str[i]; /*copy non-whitespace char to normalized string */
        j++;
    }

一个完全不同的解决方案,避免在for()循环中写入i,可能看起来像这样(顺便说一句:我在这里删除了前面的_,因为这些是重新保存的名称:

bool whitespace = false;      
    int j = 0;
    for( int i=0; str[i] != '\0'; ++ ) {
         if( isspace(str[i]) ) { // too lazy to write whitespace characters 
             if( j > 0 ) {
                 whitespace  = true;
             }
         } else {
             if( whitespace ) {
                 str[j++] = ' ';
                 whitespace = false;
             }
             str[j++] = str[i];
         }
    }
    str[j] = '\0';

相关问题