使用Valgrind排查程序错误遇阻,寻求代码修改方案
Let's break down exactly what's going on here and fix the issue step by step. First, let's parse Valgrind's key error message:
14892 Invalid read of size 1
14892 at 0x4C32D44: __strlen_sse2 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
14892 Address 0x522d04c is 0 bytes after a block of size 12 alloc'd
This means your code is reading memory right after the end of a block you allocated with malloc. The problem boils down to how you're handling C string termination—something that's easy to overlook but critical for proper string behavior.
The Root Problems in Your Code
C strings depend on a null terminator ('\0') to tell functions like printf or strlen where the string ends. Here's where you went wrong:
- Insufficient memory allocation: You used
malloc(strlen(text)), butstrlen()returns the length of the string excluding the null terminator. Your reversed string needs an extra byte to store this'\0'. - Missing null terminator: After copying and reversing characters, you never added the
'\0'to the end of your new string. This makes functions likeprintfkeep reading past your allocated memory until they hit a random null byte, triggering Valgrind's error.
Corrected Code with Explanations
Here's the fixed version of your code, with notes on each change:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> char* reverse(const char* text){ if(text == NULL){ return NULL; } size_t len = strlen(text); // Store the string length once (avoids repeated slow strlen calls) // Allocate len + 1 bytes to make space for the null terminator char *novy = malloc(len + 1); if (novy == NULL) { // Always check if malloc succeeded (prevents crashes from out-of-memory) return NULL; } // Copy and uppercase the original string's characters for(size_t j = 0; j < len; j++){ novy[j] = toupper(text[j]); } // Add the null terminator to mark the end of our new string novy[len] = '\0'; size_t p = len - 1; for(size_t i = 0; i < (len / 2); i++){ char tmp = novy[i]; novy[i] = novy[p]; novy[p] = tmp; p--; } return novy; } int main(){ char* reversed = reverse("Hello world!"); if (reversed != NULL) { // Check for NULL to avoid printing a invalid pointer printf("%s\n", reversed); free(reversed); } return 0; }
Key Fixes Explained
- Extra byte for null terminator:
malloc(len + 1)ensures we have space for both the string characters and the'\0'. - Explicit null terminator:
novy[len] = '\0'tells string-handling functions exactly where our string ends. - Cached string length: Storing
strlen(text)inlenonce improves efficiency (sincestrlenscans the entire string each time it's called) and keeps our code consistent. - Null safety checks: Adding checks for
mallocfailure andreversereturning NULL prevents potential crashes from edge cases.
Why This Fixes Valgrind's Error
With the null terminator in place and enough memory allocated, functions like printf will stop reading exactly at the end of your allocated block. Valgrind will no longer detect an "invalid read," and your string will behave as expected. The heap summary already showed no memory leaks, so this resolves the only error in your code.
内容的提问来源于stack exchange,提问作者Natalia

