如何正确复用已分配指针?解决double free or corruption (! prev)错误
Let's break down the critical bugs in your code that are causing this memory corruption error—even when you comment out the sqlite3_get_table call. Most issues stem from incorrect string handling and syntax mistakes that trigger undefined behavior.
Key Issues in Your Code
1. Syntax & Type Errors
- Missing parenthesis in malloc: Your
malloccall is missing a closing), which is a syntax error that can lead to unexpected compilation behavior:// Wrong char *query = malloc(sizeof(char) * (arr1.length * 10 + 200); // Correct char *query = malloc(sizeof(char) * (arr1.length * 10 + 200)); - Invalid for loop syntax:
0lis a long integer literal, and you're missing a semicolon in the loop condition:// Wrong for(i=0l i<arr1.length; i++){ // Correct for(i=0; i<arr1.length; i++){ } - Incorrect SQLite handle type: The first parameter to
getValuesshould be asqlite3*pointer, notsqlite3:// Wrong void getValues(sqlite3 conn, struct Arr arr1, struct Arr arr2, int *values){ // Correct void getValues(sqlite3 *conn, struct Arr arr1, struct Arr arr2, int *values){ } - Missing semicolon after free:
free(query)needs a trailing semicolon to avoid syntax errors.
2. Dangerous String Reset
The line sprintf(query, '\0') is the primary culprit for your memory corruption. Here's why:
sprintfexpects its second argument to be a format string pointer. Passing'\0'(a char with value 0) gets promoted to an integer, which is treated as a NULL pointer. This causessprintfto attempt reading from NULL, triggering undefined behavior that corrupts heap metadata.- Fix: Reset the string safely by setting the first character to the null terminator directly:
query[0] = '\0';
3. Flawed Query Construction Logic
- Misplaced
strcpy: You're callingstrcpy(query, "...")inside theiloop but outside thejloop—this means you'll overwrite the query string only once periiteration, but if the previous query was longer, you might leave leftover characters. Move thisstrcpyto the start of eachiloop to ensure a clean start. - Mismatched array length check: You're checking
j == arr1.length - 1whenjis iterating overarr2—this will cause incorrect string termination. Usej == arr2.length - 1instead. - Insufficient buffer size: Your
bufferandbuffer_don't account for the null terminator. For a numberN, the string length isceil(log10(N+1)), so you need to add 1 to the buffer size to store'\0':// Wrong char buffer[sizeof(char) * (int)(ceil(log10(arr1.arr_[j]+1)))]; // Correct char buffer[(int)(ceil(log10(arr1.arr_[j]+1)) + 1)];
4. Unhandled SQLite3 Result
While you commented out sqlite3_get_table, remember that when you use it, you must free the result array with sqlite3_free_table(res) to avoid memory leaks.
Corrected Code
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <sqlite3.h> #include <string.h> struct Arr{ int length; int *arr_; }; void getValues(sqlite3 *conn, struct Arr arr1, struct Arr arr2, int *values){ int i, j; int state, nrow, ncolumn; char **res; char *err_msg = 0; // Allocate query buffer with enough space size_t query_size = sizeof(char) * (arr1.length * 10 + 200); char *query = malloc(query_size); if (!query) { // Always check malloc success fprintf(stderr, "Malloc failed!\n"); return; } for(i=0; i<arr1.length; i++){ // Reset query to empty string at the start of each iteration query[0] = '\0'; // Start building the query strcpy(query, "select * from table1 where value1 in ("); for(j=0; j<arr2.length; j++){ // Calculate buffer size with room for null terminator int buf_len = (int)(ceil(log10(arr1.arr_[j]+1)) + 1); char buffer[buf_len]; sprintf(buffer, "%d", arr1.arr_[j]); // Use strncat to avoid overflow (optional but safer) strncat(query, buffer, query_size - strlen(query) - 1); if(j == arr2.length - 1){ strncat(query, " ) and value2 = ", query_size - strlen(query) - 1); int buf_len_ = (int)(ceil(log10(arr2.arr_[i]+1)) + 1); char buffer_[buf_len_]; sprintf(buffer_, "%d", arr2.arr_[i]); strncat(query, buffer_, query_size - strlen(query) - 1); strncat(query, ";", query_size - strlen(query) - 1); } else { strncat(query, " , ", query_size - strlen(query) - 1); } } printf("query: %s\n", query); state = sqlite3_get_table(conn, query, &res, &nrow, &ncolumn, &err_msg); if (state != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); } else { // Process your result here // ... sqlite3_free_table(res); // Don't forget to free the result! } } free(query); }
Why This Fixes the Error
The sprintf(query, '\0') line was corrupting the heap metadata that malloc/free uses to track allocated blocks. By replacing that with a safe string reset, fixing the buffer overflows, and correcting syntax errors, you eliminate the undefined behavior that was triggering the "double free or corruption" message.
内容的提问来源于stack exchange,提问作者Erwin Zangwill

