неинициализированное значение и оптимизация лязга - PullRequest
0 голосов
/ 03 сентября 2018

Я создал программу для печати строки "Hello World", как показано ниже:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void callString(char *_string);
int main() 
{
    char *myString;

// Allocating memory
    myString = (char *)malloc(
      (unsigned long)strlen(myString)
      * sizeof(char)
    );

    myString = "Hello World!";
    callString(myString);

    // should I free(myString) here?

    return 0;
}

static void 
callString(char *_string) 
{ 
    printf("%s\n", _string);
}

Составление и запуск отчетов:

$ clang -Wall -Weverything -g hello.c -o hello
$ ./hello 
Hello World!

выглядит хорошо, но затем, если я пытаюсь профилировать память с помощью Valgrind, я получаю:

$ valgrind \
--track-origins=yes \
--leak-check=full \
--leak-resolution=high \
--num-callers=50 \
./hello

==31692== Memcheck, a memory error detector
==31692== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31692== Using Valgrind-3.14.0.GIT and LibVEX; rerun with -h for copyright info
==31692== Command: ./hello
==31692== 
==31692== Use of uninitialised value of size 8
==31692==    at 0x483ACC2: __strlen_sse2 (vg_replace_strmem.c:462)
==31692==    by 0x109177: main (hello.c:9)
==31692==  Uninitialised value was created by a stack allocation
==31692==    at 0x109160: main (hello.c:7)
==31692== 
==31692== Use of uninitialised value of size 8
==31692==    at 0x483ACD4: __strlen_sse2 (vg_replace_strmem.c:462)
==31692==    by 0x109177: main (hello.c:9)
==31692==  Uninitialised value was created by a stack allocation
==31692==    at 0x109160: main (hello.c:7)
==31692== 
Hello World!
==31692== 
==31692== HEAP SUMMARY:
==31692==     in use at exit: 1 bytes in 1 blocks
==31692==   total heap usage: 2 allocs, 1 frees, 1,025 bytes allocated
==31692== 
==31692== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
==31692==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==31692==    by 0x109183: main (hello.c:9)
==31692== 
==31692== LEAK SUMMARY:
==31692==    definitely lost: 1 bytes in 1 blocks
==31692==    indirectly lost: 0 bytes in 0 blocks
==31692==      possibly lost: 0 bytes in 0 blocks
==31692==    still reachable: 0 bytes in 0 blocks
==31692==         suppressed: 0 bytes in 0 blocks
==31692== 
==31692== For counts of detected and suppressed errors, rerun with: -v
==31692== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

Если я компилирую с флагами оптимизации на уровне -O3, я получаю зеленый сигнал.

$ valgrind \
--track-origins=yes \
--leak-check=full \
--leak-resolution=high \
--num-callers=50 \
./hello
==32000== Memcheck, a memory error detector
==32000== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32000== Using Valgrind-3.14.0.GIT and LibVEX; rerun with -h for copyright info
==32000== Command: ./hello
==32000== 
Hello World!
==32000== 
==32000== HEAP SUMMARY:
==32000==     in use at exit: 0 bytes in 0 blocks
==32000==   total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==32000== 
==32000== All heap blocks were freed -- no leaks are possible
==32000== 
==32000== For counts of detected and suppressed errors, rerun with: -v
==32000== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Похоже, оптимизация устраняет некоторые проблемы с памятью. Что не так с фрагментом кода? Какой из них называется «Использование неинициализированной стоимости»? MyString? Как я могу инициализировать это?

Редактировать: Как советовал @Lundin, я усвоил урок не назначать строки с = напрямую. Благодарю. Фиксированная кодовая часть =

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void callString(char *_string);
int main() 
{
    char *myString;
    myString = (char *)malloc(
    (unsigned long)strlen(myString)+1 * sizeof(char)
    );
    strncpy(myString, "Hello World", 11);
    callString(myString);

    free(myString);
    return 0;
}

static void 
callString(char *_string) 
{ 
    printf("%s\n", _string);
}

Спасибо @Mat тоже

1 Ответ

0 голосов
/ 03 сентября 2018

У вас 3 проблемы:

  • myString неинициализирован, поэтому вызывать strlen(myString) не имеет смысла. Вам нужно установить что-то значимое перед вызовом strlen

  • Ваш malloc-вызов неверен, вам не следует выделять strlen(...) * sizeof(char), а скорее strlen(...) + 1, поскольку строки в C завершаются нулем, и вы должны выделить место для нулевого терминатора. Кроме того, умножать на sizeof(char) не нужно, поскольку оно гарантированно равно 1.

  • После того, как вы используете malloc, вы не можете назначить указатель на что-то другое: myString = "Hello World!";. Это то, на что жалуется Valgrind, это утечка памяти. Строки копируются с использованием strcpy, а не с присваиванием =.

Кроме того, хорошей практикой является free() всей памяти в конце программы.

...