我正在编写一个程序,其中输入将从stdin中获取。第一个输入将是一个整数,它说要从stdin读取的字符串数。我刚刚将字符串字符读为动态分配的内存,并在字符串结束后将其显示。
但是,当字符串大于分配的尺寸时,我将使用Realloc重新定位内存。但是,即使我使用memcpy,该程序也有效。不使用memcpy是不确定的行为吗?但是在C中使用Realloc的示例不使用Memcpy。那么哪一种是正确的方法呢?我的程序在下面显示正确吗?
/* ss.c
* Gets number of input strings to be read from the stdin and displays them.
* Realloc dynamically allocated memory to get strings from stdin depending on
* the string length.
*/
#include <stdio.h>
#include <stdlib.h>
int display_mem_alloc_error();
enum {
CHUNK_SIZE = 31,
};
int display_mem_alloc_error() {
fprintf(stderr, "nError allocating memory");
exit(1);
}
int main(int argc, char **argv) {
int numStr; //number of input strings
int curSize = CHUNK_SIZE; //currently allocated chunk size
int i = 0; //counter
int len = 0; //length of the current string
int c; //will contain a character
char *str = NULL; //will contain the input string
char *str_cp = NULL; //will point to str
char *str_tmp = NULL; //used for realloc
str = malloc(sizeof(*str) * CHUNK_SIZE);
if (str == NULL) {
display_mem_alloc_error();
}
str_cp = str; //store the reference to the allocated memory
scanf("%dn", &numStr); //get the number of input strings
while (i != numStr) {
if (i >= 1) { //reset
str = str_cp;
len = 0;
}
c = getchar();
while (c != 'n' && c != 'r') {
*str = (char *) c;
printf("nlen: %d -> *str: %c", len, *str);
str = str + 1;
len = len + 1;
*str = ' ';
c = getchar();
if (curSize/len == 1) {
curSize = curSize + CHUNK_SIZE;
str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
if (str_tmp == NULL) {
display_mem_alloc_error();
}
memcpy(str_tmp, str_cp, curSize); // NB: seems to work without memcpy
printf("nstr_tmp: %d", str_tmp);
printf("nstr: %d", str);
printf("nstr_cp: %dn", str_cp);
}
}
i = i + 1;
printf("nEntered string: %sn", str_cp);
}
return 0;
}
/* -----------------
//input-output
gcc -o ss ss.c
./ss < in.txt
// in.txt
1
abcdefghijklmnopqrstuvwxyzabcdefghij
// output
// [..snip..]
Entered string:
abcdefghijklmnopqrstuvwxyzabcdefghij
-------------------- */
谢谢。
您的程序不太正确。您需要删除与memcpy
的呼叫,以避免偶尔诊断出bug。
来自Realloc Man Page
realloc()函数更改了指向的内存块的大小 由PTR到大小字节。内容将在该范围内保持不变 从该地区的开始到新旧的最低限度 尺寸
因此,您无需在realloc
之后致电memcpy
。实际上,这样做是错误的,因为您以前的堆单元可能已被释放在realloc
呼叫中。如果被释放,现在它指向具有不可预测内容的内存。
c11标准(PDF),第7.22.3.4节:
realloc
函数交易了PTR指向的旧对象,并将指针返回到具有大小规定大小的新对象。新对象的内容应与Dealllocation之前的旧对象相同,直到新尺寸和旧尺寸的较小。超出旧对象大小的新对象中的任何字节都有不确定的值。
简而言之,memcpy
是不必要的,确实是错误的。错误的原因有两个:
- 如果
realloc
具有free
D您以前的内存,则您正在访问不是您的内存。 - 如果
realloc
刚刚放大了您以前的内存,则为memcpy
提供了两个指向同一区域的指针。memcpy
在其两个输入指针上都有restrict
预选赛,这意味着如果它们指向同一对象,则是未定义的行为。(旁注:memmove
没有此限制)
realloc放大为字符串保留的内存大小。如果可以在不移动数据的情况下扩大它,则这些将保持到位。如果不能,则它会在啤酒记忆库中进行malloc,而memcpy本身是上一个内存库中包含的数据。
简而
从"人"页面:
realloc()函数试图更改分配的大小 由PTR到大小,然后返回PTR。如果没有足够的空间 放大由PTR指向的内存分配,Realloc()创建了一个新的 分配,副本同样适合PTR指向的旧数据 转到新的分配,释放旧分配,然后返回指针 分配的内存。如果ptr为null,则realloc()与呼叫相同 到malloc()大小字节。如果大小为零,并且PTR不是零,则是新的, 最小尺寸的对象是分配的,原始对象已释放。什么时候 延长由Calloc(3)分配的区域,Realloc(3)不瓜兰 - Tee额外的内存也为零。