- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我的代码工作正常,但我收到 valgrind 错误。我想知道如何更正我的代码以正确使用这些 malloc 和 free 语句与 char * * dest。请不要告诉我不要 malloc 和 free 除非我在不正确的位置这样做。拥有 answer03.c 中 strcat_ex 的一个或两个更正代码,或者解释我对 malloc、free 和 malloc 之后的初始化的误解,将不胜感激。对于这篇长帖子,我提前表示歉意,但我想提供所有必要的东西。
更多信息:我主要关注方法 strcat_ex(这与 strncat 不同——阅读函数的描述以了解与 int *n 的区别)。问题出现的事实是我需要在 dest (char **) 中重新分配字符串 (char *) 的参数内存,如果它没有分配足够的空间,并且在我 malloc 之后它没有被初始化。这对我来说没有意义如何在 malloc 之后初始化“堆”内存。我不相信初始化必须在 malloc 之后发生。
注意:pa03.c 和 answer03.h 根本不应该改变。
这是相关的 valgrind 错误 (memcheck.log):
==28717== 1 errors in context 7 of 10:
==28717== Conditional jump or move depends on uninitialised value(s)
==28717== at 0x402D09C: strcat (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==28717== by 0x8048F98: strcat_ex (answer03.c:29)
==28717== by 0x8048631: main (pa03.c:16)
==28717== Uninitialised value was created by a heap allocation
==28717== at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==28717== by 0x8048F46: strcat_ex (answer03.c:21)
==28717== by 0x8048631: main (pa03.c:16)
==28717==
==28717== ERROR SUMMARY: 10 errors from 10 contexts (suppressed: 0 from 0)
引用的行:
第 16 行(来自 pa03.c)不应更改。作为调用方法参数 def、n、src 和 return 变量结果的示例在 pa03.c 中声明如下:
result=strcat_ex(&dest, &n, src);
第 21 行(来自 answer03.c):
char * buffer = malloc(1 + 2 * (sizeOfDest + strlen(src)));
第 29 行(来自 answer03.c):
buffer = strcat(buffer,src);
这里是相关的源代码。这是 valgrind 错误所在,需要 stackoverflow 知识 (answer03.c):
编辑:已添加注释并注释掉行以删除我在代码中与我的问题直接无关的错误。对于这些令人发指的错误,我深表歉意,但保留了一些台词以帮助 future 的读者理解。
#include "answer03.h"
#include <string.h>
char * strcat_ex(char * * dest, int * n, const char * src)
{
//Edit: Removed Line Below - Irrelevant variable resplaced with *n
//int sizeOfDest;
if(*dest == NULL)
{
*n = 0;
}
else
{
//Edit: Removed Line Below - variable replaced with *n
//sizeOfDest = strlen(*dest);
}
//Edit: Removed Line Below
//if(*dest != NULL && sizeOfDest >= 1 + sizeOfDest + strlen(src))
//Edit: Corrected Line
if(*dest !=NULL && *n >= 1 + strlen(*dest) + strlen(src))
{
strcat(*dest, src);
}
else
{
//Edit: *n replaced sizeOfDest and changes needed to be made to reflect this. Commented out lines were incorrect and irrelevant. Lines directly below them are the corrected versions, until you reach the next blank line
//*n = 1 + 2 * (sizeOfDest + strlen(src));
if(*dest != NULL)
*n = 1 + 2 * (strlen(*dest) + strlen(src));
else
*n = 1 + 2 * strlen(src);
//char * buffer = malloc(1 + 2 * (sizeOfDest + strlen(src)));
char * buffer = malloc(sizeof(char) * *n);
if(*dest != NULL)
{
strcpy(buffer, *dest);
free(*dest);
}
*dest = malloc(sizeof(buffer));
buffer = strcat(buffer,src);
*dest = buffer;
}
return *dest;
}
低于此点的所有内容都应保持不变并且已知是正确的:
我的编译语句(Makefile):
gcc -Wall -Wshadow -g pa03.c answer03.c -o pa03
我的 valgrind 语句(Makefile):
valgrind --tool=memcheck --leak-check=full --verbose --track-origins=yes --log-file=memcheck.log ./pa03
这是 strcat_ex 的函数定义(answer03.h):
#ifndef PA03_H
#define PA03_H
#include <stdlib.h>
/**
* Append the C-string 'src' to the end of the C-string '*dest'.
*
* strcat_ex(...) will append the C-string 'src' to the end of the string
* at '*dest'. The parameter 'n' is the address of a int that specifies how
* many characters can safely be stored in '*dest'.
*
* If '*dest' is NULL, or if '*dest' is not large enough to contain the result
* (that is, the sum of the lengths of *dest, src, and the null byte), then
* strcat_ex will:
* (1) malloc a new buffer of size 1 + 2 * (strlen(*dest) + strlen(src))
* (2) set '*n' to the size of the new buffer
* (3) copy '*dest' into the beginning of the new buffer
* (4) free the memory '*dest', and then set '*dest' to point to the new buffer
* (5) concatenate 'src' onto the end of '*dest'.
*
* Always returns *dest.
*
* Why do we need to pass dest as char * *, and n as int *?
* Please see the FAQ for an answer.
*
* Hint: These <string.h> functions will help: strcat, strcpy, strlen.
* Hint: Leak no memory.
*/
char * strcat_ex(char * * dest, int * n, const char * src);
//...
下面是调用source作为测试的相关代码(pa03.c):
#include <stdio.h>
#include <string.h>
#include "answer03.h"
int main(int argc, char **argv)
{
char * src;
char * dest;
char * result;
int n;
src="World!";
dest=NULL;
result=strcat_ex(&dest, &n, src);
printf("src=\"World!\";\ndest=NULL;\nstrcat_ex(&dest, &n, src);\n --> gives %s with n=%d\n",result,n);
result=strcat_ex(&dest, &n, "");
printf("Then strcat_ex(&dest, &n, \"\") yields --> gives %s with n=%d\n",result,n);
strcpy(dest,"abc");
result=strcat_ex(&dest, &n, "def");
printf("Then strcpy(dest,\"abc\"); strcat_ex(&dest, &n, \"def\") yields --> gives %s with n=%d\n",result,n);
free(dest);
//...
这里是相关的输出(来自 pa03.c 的打印语句):请注意,这是正确的输出(我当前的代码能够生成)。
src="World!";
dest=NULL;
strcat_ex(&dest, &n, src);
--> gives World! with n=13
Then strcat_ex(&dest, &n, "") yields --> gives World! with n=13
Then strcpy(dest,"abc"); strcat_ex(&dest, &n, "def") yields --> gives abcdef with n=13
//...
最后的话:
我附上了编译此代码所需的文件以及在 linux 中使用 gcc 和 valgrind 的 valgrind 错误日志。 valgrind 中还有更多内容,但我发布了我认为最相关的内容。提前致谢。
Zip 包括所有文件:
http://www.filedropper.com/files_11
最佳答案
您当前的功能已完全损坏。它包含无法看到结果的逻辑,至少有一次内存泄漏,以及未经检查的连接到未初始化的目标缓冲区。其中有很多错误:
sizeofDest
不仅指示当前目标字符串的存储,而且指示任何串联操作的容量。这是完全错误的,这就是为该函数提供 n
的原因。*dest = malloc(sizeof(buffer));
不仅分配了完全不正确的内存大小(指针的大小;而不是它指向的内容),而且简而言之两行后泄漏说分配。N
,表达式 N >= N + 1 + M
,其中 M 是一个非负值,不可能永远是真的。n
提供的当前目标缓冲区大小。该值对该算法至关重要,因为它决定了目标缓冲区的真实大小,并与 *dest* 中的当前字符串长度相结合
,将最终决定是否需要调整大小。这是正确执行此功能的一种方法:
char *strcat_ex(char ** dest, int * n, const char * src)
{
size_t dst_len = 0, src_len = strlen(src);
// determine current string length held in *dest
if (*dest && **dest)
dst_len = strlen(*dest);
size_t req_len = dst_len + src_len + 1;
// is space already available for the concatination?
if (*dest && *n >= req_len)
{
// we already know where the target address of the
// concatination is, and we already know the length of
// what is being copied. just copy chars.
if (src_len)
memcpy(*dest+dst_len, src, src_len+1);
}
else
{
// resize is required
void *tmp = realloc(*dest, req_len);
if (tmp != NULL)
{
// resize worked, original content of *dest retained, so
// we can once again simply copy bytes.
*dest = tmp;
memcpy(*dest+dst_len, src, src_len+1);
*n = (int)req_len;
}
else
{
perror("Failed to resize target buffer");
exit(EXIT_FAILURE);
}
}
return *dest;
}
我对这个设计的作者非常不满,因为他们选择了 int
作为保存目标缓冲区大小的变量。这个大小显然永远不会是负,并且除了所有标准库大小操作所使用的相同类型 size_t
之外,使用任何其他类型都是没有意义的。我会提请设计它的人注意这一点。
简单测试
int main()
{
char *dst = NULL;
int n = 0;
strcat_ex(&dst, &n, "some string");
printf("%s : %d\n", dst, n);
strcat_ex(&dst, &n, " more data");
printf("%s : %d\n", dst, n);
*dst = 0; // zero-term the string
strcat_ex(&dst, &n, "after empty");
printf("%s : %d\n", dst, n);
strcat_ex(&dst, &n, " and more");
printf("%s : %d\n", dst, n);
strcat_ex(&dst, &n, " and still more");
printf("%s : %d\n", dst, n);
}
输出
some string : 12
some string more data : 22
after empty : 22
after empty and more : 22
after empty and more and still more : 36
你的测试
运行您的测试程序会产生以下结果:
src="World!";
dest=NULL;
strcat_ex(&dest, &n, src);
--> gives World! with n=7
Then strcat_ex(&dest, &n, "") yields --> gives World! with n=7
Then strcpy(dest,"abc"); strcat_ex(&dest, &n, "def") yields --> gives abcdef with n=7
关于c - 未初始化的堆分配误解(代码有效——需要更正以消除 Valgrind 错误),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28549515/
我是 Spring 新手,这就是我想要做的事情: 我正在使用一个基于 Maven 的库,它有自己的 Spring 上下文和 Autowiring 字段。 它的bean配置文件是src/test/res
我在我的测试脚本中有以下列表初始化: newSequenceCore=["ls", "ns", "*", "cm", "*", "ov", "ov", "ov", "ov", "kd"] (代表要在控
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Class construction with initial values 当我查看 http://en.
我得到了成员变量“objectCount”的限定错误。编译器还返回“ISO C++ 禁止非常量静态成员的类内初始化”。这是主类: #include #include "Tree.h" using n
我有如下所示的a.h class A { public: void doSomething()=0; }; 然后我有如下所示的b.h #include "a.h" class b: publi
我需要解析 Firebase DataSnapshot (一个 JSON 对象)转换成一个数据类,其属性包括 enum 和 list。所以我更喜欢通过传递 DataSnapshot 来手动解析它进入二
我使用 JQuery 一段时间了,我总是使用以下代码来初始化我的 javascript: $(document).ready( function() { // Initalisation logic
这里是 Objective-C 菜鸟。 为什么会这样: NSString *myString = [NSString alloc]; [myString initWithFormat:@"%f", s
我无法让核心数据支持的 NSArrayController 在我的代码中正常工作。下面是我的代码: pageArrayController = [[NSArrayController alloc] i
我对这一切都很陌生,并且无法将其安装到我的后端代码中。它去哪里?在我的页脚下面有我所有的 JS? 比如,这是什么意思: Popup initialization code should be exec
这可能是一个简单的问题,但是嘿,我是初学者。 所以我创建了一个程序来计算一些东西,它目前正在控制台中运行。我决定向其中添加一个用户界面,因此我使用 NetBeans IDE 中的内置功能创建了一个 J
我有 2 个 Controller ,TEST1Controller 和 TEST2Controller 在TEST2Controller中,我有一个initialize()函数设置属性值。 如果我尝
据我所知, dependentObservable 在声明时会进行计算。但如果某些值尚不存在怎么办? 例如: var viewModel ={}; var dependentObservable1 =
我正在阅读 POODR 这本书,它使用旧语法进行默认值初始化。我想用新语法实现相同的功能。 class Gear attr_reader :chainring, :cog, :wheel de
我按照 polymer 教程的说明进行操作: https://www.polymer-project.org/3.0/start/install-3-0 (我跳过了可选部分) 但是,在我执行命令“po
很抱歉问到一个非常新手的Kotlin问题,但是我正在努力理解与构造函数和初始化有关的一些东西。 我有这个类和构造函数: class TestCaseBuilder constructor(
假设我们有一个包含 30 列和 30 行的网格。 生命游戏规则简而言之: 一个小区有八个相邻小区 当一个细胞拥有三个存活的相邻细胞时,该细胞就会存活 如果一个细胞恰好有两个或三个活的相邻细胞,那么它就
我是 MQTT 和 Android 开放附件“AOA” 的新手。在阅读教程时,我意识到,在尝试写入 ByteArrayOutputStream 类型的变量之前,应该写入 0 或 0x00首先到该变量。
我有 2 个 Controller ,TEST1Controller 和 TEST2Controller 在TEST2Controller中,我有一个initialize()函数设置属性值。 如果我尝
我有一个inotify /内核问题。我正在使用“inotify” Python项目进行观察,但是,我的问题仍然是固有的关于inotify内核实现的核心。 Python inotify项目处理递归ino
我是一名优秀的程序员,十分优秀!