- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有这个代码:
static void foo(char *string1, char *string2)
{
char *string1_copy= malloc(strlen(string1));
strcpy(string1_copy, haystack);
char *string2_copy = malloc(strlen(string2));
strcpy(string2_copy, needle);
}
我必须复制string1
和string2
修改其副本并保留原件。这做了它应该做的事情并且编译没有错误,但是当我运行时:
valgrind --leak-check=full -v ./myProgram
我明白了:
==20595== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
==20595==
==20595== 1 errors in context 1 of 3:
==20595== Invalid read of size 1
==20595== at 0x4C376F4: strstr (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20595== by 0x108CED: grep (myProgram.c:87)
==20595== by 0x109023: main (myProgram.c:214)
==20595== Address 0x522e3b3 is 0 bytes after a block of size 3 alloc'd
==20595== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20595== by 0x108CA5: grep (myProgram.c:77)
==20595== by 0x109023: main (myProgram.c:214)
==20595==
==20595==
==20595== 1 errors in context 2 of 3:
==20595== Invalid write of size 1
==20595== at 0x4C32E0D: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20595== by 0x108CBC: grep (myProgram.c:78)
==20595== by 0x109023: main (myProgram.c:214)
==20595== Address 0x522e3b3 is 0 bytes after a block of size 3 alloc'd
==20595== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20595== by 0x108CA5: grep (myProgram.c:77)
==20595== by 0x109023: main (myProgram.c:214)
==20595==
==20595==
==20595== 1 errors in context 3 of 3:
==20595== Invalid write of size 1
==20595== at 0x4C32E0D: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20595== by 0x108C91: grep (myProgram.c:75)
==20595== by 0x109023: main (myProgram.c:214)
==20595== Address 0x522e362 is 0 bytes after a block of size 18 alloc'd
==20595== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20595== by 0x108C7A: grep (myProgram.c:74)
==20595== by 0x109023: main (myProgram.c:214)
==20595==
==20595== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
这正是我用 strcpy()
创建这两个副本的地方我在哪里读到它们 strstr()
。有没有办法避免这种情况,或者我不应该使用 strcpy()
这里?是strlen(string)
我传递的字符串大小不正确?
最佳答案
您的分配提出了经典的Off-By-One问题。 C 中的字符串始终以 nul 字符 结尾。这就是字符串与字符数组的区别。要为源字符串 src
的副本正确分配存储空间,您必须分配 strlen(src) + 1
字节。
你的foo
函数没有什么意义。在 foo
中,您分配存储空间,例如char *string1_copy= malloc(strlen(string1));
但无法让您的程序在函数返回后使用分配的内存。 void
函数不返回任何值,从而消除了确定复制成功/失败的任何方法,并且没有额外的指针到指针参数提供任何方法来更新原始地址处的指针。此外,分配存储空间后,函数返回,并且您会丢失保存每次分配的起始地址的指针,从而产生内存泄漏。
当想要复制两个字符串时,编写一个复制两个字符串的函数是没有意义的。该一次性功能几乎没有可重用性。相反,只需编写一个复制单个字符串的函数,提供有意义的返回以允许确定成功/失败,然后为每个需要复制的字符串调用该函数一次。
对函数的重构不仅可以让您充分验证每个分配,而且还可以在您需要复制字符串时随时重用。事实上,POSIX 提供了一个 strdup()
函数来完成此任务,但您可以轻松编写自己的函数以确保严格的 C 标准合规性。
此类函数的合理实现可以写为:
/* returns pointer to allocated copy of src, or NULL on failure */
char *dupstr (const char *src)
{
size_t len = strlen (src); /* get length of src */
char *dest = malloc (len + 1); /* allocate length + 1 bytes */
if (!dest) { /* validate EVERY allocation */
perror ("dupstr() malloc-dest");
return NULL;
}
return memcpy (dest, src, len + 1); /* copy src to dest, return ptr */
}
(注意:您还可以添加对 if (!src)
的检查,以确保传递的指针不是 NULL
——即留给你了)
这是一个简单的函数,它获取原始字符串的长度(作为 const char*
传递),然后分配 len + 1
字节以提供足够的存储空间验证分配并在失败时提供错误并返回NULL
。然后,该函数使用 memcpy()
将 src
复制到目标字符串 dest
,返回指向 dest
的指针
(注意:不需要使用strcpy()
。此时您已经计算了src
的长度,并且无需使用 strcpy()
再次扫描字符串结尾)。
复制并输出所有程序参数的简单实现可能是:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* returns pointer to allocated copy of src, or NULL on failure */
char *dupstr (const char *src)
{
size_t len = strlen (src); /* get length of src */
char *dest = malloc (len + 1); /* allocate length + 1 bytes */
if (!dest) { /* validate EVERY allocation */
perror ("dupstr() malloc-dest");
return NULL;
}
return memcpy (dest, src, len + 1); /* copy src to dest, return ptr */
}
int main (int argc, char **argv) {
char *copies[argc]; /* VLA of argc pointers to char */
for (int i = 0; i < argc; i++) { /* loop over each argument */
if ((copies[i] = dupstr (argv[i]))) { /* duplicate in copies[i] */
puts (copies[i]); /* output copy */
free (copies[i]); /* free copy */
}
}
}
示例使用/输出
$ ./bin/dupstr my dog has fleas and my cat has none - lucky cat
./bin/dupstr
my
dog
has
fleas
and
my
cat
has
none
-
lucky
cat
内存使用/错误检查
在您编写的动态分配内存的任何代码中,对于分配的任何内存块,您都有两个责任:(1) 始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或在分配的 block 的范围之外进行写入,尝试读取或基于未初始化的值进行条件跳转,最后,确认您释放了已分配的所有内存。
对于 Linux,valgrind
是正常选择。每个平台都有类似的内存检查器。它们使用起来都很简单,只需通过它运行您的程序即可。
$ valgrind ./bin/dupstr my dog has fleas and my cat has none - lucky cat
==6014== Memcheck, a memory error detector
==6014== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6014== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==6014== Command: ./bin/dupstr my dog has fleas and my cat has none - lucky cat
==6014==
./bin/dupstr
my
dog
has
fleas
and
my
cat
has
none
-
lucky
cat
==6014==
==6014== HEAP SUMMARY:
==6014== in use at exit: 0 bytes in 0 blocks
==6014== total heap usage: 14 allocs, 14 frees, 1,086 bytes allocated
==6014==
==6014== All heap blocks were freed -- no leaks are possible
==6014==
==6014== For counts of detected and suppressed errors, rerun with: -v
==6014== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认您已释放分配的所有内存并且不存在内存错误。
仔细检查一下,如果您还有其他问题,请告诉我。
关于正确使用strcpy()并避免valgrind中读写大小错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58887174/
我们已经有一个使用 AnyEvent 的库。它在内部使用 AnyEvent,并最终返回一个值(同步 - 不使用回调)。有什么方法可以将这个库与 Mojolicious 一起使用吗? 它的作用如下: #
我想从 XSD 文件生成带有 JAXB 的 Java 类。 问题是,我总是得到一些像这样的类(删除了命名空间): public static class Action { @X
我有一个关于 html 输入标签或 primefaces p:input 的问题。为什么光标总是自动跳转到输入字段。我的页面高度很高,因此您需要向下滚动。输入字段位于页面末尾,光标自动跳转(加载)到页
我今天在考虑面向对象设计,我想知道是否应该避免 if 语句。我的想法是,在任何需要 if 语句的情况下,您都可以简单地创建两个实现相同方法的对象。这两个方法实现只是原始 if 语句的两个可能的分支。
String graphNameUsed = graphName.getName(); if (graphType.equals("All") || graphType.equals(
我有一张友谊 table CREATE TABLE IF NOT EXISTS `friendList` ( `id` int(10) NOT NULL, `id_friend` int(10
上下文 Debian 64。Core 2 二人组。 摆弄循环。我使用了同一循环的不同变体,但我希望尽可能避免条件分支。 但是,即使我认为它也很难被击败。 我考虑过 SSE 或位移位,但它仍然需要跳转(
我最近在 Java 中创建了一个方法来获取字符串的排列,但是当字符串太长时它会抛出这个错误:java.lang.OutOfMemoryError: Java heap space我确信该方法是有效的,
我正在使用 (C++) 库,其中需要使用流初始化对象。库提供的示例代码使用此代码: // Declare the input stream HfstInputStream *in = NULL; tr
我有一个 SQL 查询,我在 WHERE 子句中使用子查询。然后我需要再次使用相同的子查询将其与不同的列进行比较。 我假设没有办法在子查询之外访问“emp_education_list li”? 我猜
我了解到在 GUI 线程上不允许进行网络操作。对我来说还可以。但是为什么在 Dialog 按钮点击回调上使用这段代码仍然会产生 NetworkOnMainThreadException ? new T
有没有办法避免在函数重定向中使用 if 和硬编码字符串,想法是接收一个字符串并调用适当的函数,可能使用模板/元编程.. #include #include void account() {
我正在尝试避免客户端出现 TIME_WAIT。我连接然后设置 O_NONBLOCK 和 SO_REUSEADDR。我调用 read 直到它返回 0。当 read 返回 0 时,errno 也为 0。我
我正在开发 C++ Qt 应用程序。为了在应用程序或其连接的设备出现故障时帮助用户,程序导出所有内部设置并将它们存储在一个普通文件(目前为 csv)中。然后将此文件发送到公司(例如通过邮件)。 为避免
我有一组具有公共(public)父类(super class)的 POJO。这些存储在 superclass 类型的二维数组中。现在,我想从数组中获取一个对象并使用子类 的方法。这意味着我必须将它们转
在我的代码中,当 List 为 null 时,我通常使用这种方法来避免 for 语句中的 NullPointerException: if (myList != null && myList.size
我正在尝试避免客户端出现 TIME_WAIT。我连接然后设置 O_NONBLOCK 和 SO_REUSEADDR。我调用 read 直到它返回 0。当 read 返回 0 时,errno 也为 0。我
在不支持异常的语言和/或库中,许多/几乎所有函数都会返回一个值,指示其操作成功或失败 - 最著名的例子可能是 UN*X 系统调用,例如 open( ) 或 chdir(),或一些 libc 函数。 无
我尝试按值提取行。 col1 df$col1[col1 == "A"] [1] "A" NA 当然我只想要“A”。如何避免 R 选择 NA 值?顺便说一句,我认为这种行为非常危险,因为很多人都会陷入
我想将两个向量合并到一个数据集中,并将其与函数 mutate 集成为 5 个新列到现有数据集中。这是我的示例代码: vector1% rowwise()%>% mutate(vector2|>
我是一名优秀的程序员,十分优秀!