C中的缓冲区大小
当以C语言提供缓冲区大小时,我怎么知道剩下多少以及何时需要停止使用内存?C中的缓冲区大小
例如,如果我写的功能是这样的:
void ascii_morse (lookuptable *table, char* morse, char* ascii, int morse_size) {
}
在这个应用程序,我将传递一个字符串(ASCII),我会把它转换成使用一些其他功能,每个ASCII转换为莫尔斯字符莫尔斯。我面临的问题是如何确保我不超过缓冲区大小。我甚至不知道何时使用缓冲区大小,或者我每次使用缓冲区大小时都会减少缓冲区大小。
当然的输出将是莫尔斯(所以我会添加字符串莫尔斯,但我想我知道如何做到这一点,它只是缓冲区的大小是什么,是很难理解我)
如果您需要更多的信息来了解问题,请告诉我,我尽力解释它。
您需要将缓冲区大小和指针一起传递。
int
ascii_to_morse(lookuptable *table,
char* morse, int morse_size,
char* ascii);
缓冲区大小不一定与字符串的当前长度相同(可以使用strlen找到)。
上面给出的函数将读取ascii字符串(不需要知道缓冲区大小,因此不会传递),并写入由morse指向的大小为morse_size的缓冲区。它返回写入的字节数(不包括空值)。
编辑:这里有这个功能,虽然它没有使用莫尔斯电码正确的价值观,展示了如何管理缓存的实现:
typedef void lookuptable; // we ignore this parameter below anyway
// but using void lets us compile the code
int
ascii_to_morse(lookuptable *table,
char* morse, int morse_size,
char* ascii)
{
if (!ascii || !morse || morse_size < 1) { // check preconditions
return 0; // and handle it as appropriate
// you may wish to do something else if morse is null
// such as calculate the needed size
}
int remaining_size = morse_size;
while (*ascii) { // false when *ascii == '\0'
char* mc_for_letter = ".-"; //BUG: wrong morse code value
++ascii;
int len = strlen(mc_for_letter);
if (remaining_size <= len) { // not enough room
// 'or equal' because we must write a '\0' still
break;
}
strcpy(morse, mc_for_letter);
morse += len; // keep morse always pointing at the next location to write
remaining_size -= len;
}
*morse = '\0';
return morse_size - remaining_size;
}
// test the above function:
int main() {
char buf[10];
printf("%d \"%s\"\n", ascii_to_morse(0, buf, sizeof buf, "aaa"), buf);
printf("%d \"%s\"\n", ascii_to_morse(0, buf, sizeof buf, "a"), buf);
printf("%d \"%s\"\n", ascii_to_morse(0, buf, sizeof buf, "aaaaa"), buf);
return 0;
}
所以例如,如果我通过了一个10的缓冲区大小和字符串是“你好世界”我说缓冲区大小 - 每次我阅读的字符? – c2009l123 2009-11-19 00:02:37
不,由于C中的字符串以空字节结尾,因此您可以使用'strlen'来获取长度。担心缓冲区大小适用于您要写入的字符串。 – Schwern 2009-11-19 00:08:27
morse_size是结果的大小。你必须计算你输入'莫尔斯'时有多少个字符,并在morse_size -1时停止(因为你想为nul终止符保留最后一个字符)。当你阅读'ascii'中的字符时,你只是阅读,直到结束,这将是nul字符。 – nos 2009-11-19 00:10:27
缓冲区的大小不能推断单独的指针。它需要作为参数传递,或者以某种方式知道(如从DEFINE值或其他常量)或隐式知道...(后者,如果大小以某种方式改变但是这种改变是隐含的方法是“危险的”没有反映在使用缓冲区的地方......)
或者,更典型地在输入缓冲区(函数将读取的缓冲区)的情况下,缓冲区的末端可以用特殊标记字符或这样的字符序列。
它已通过,但我如何使用它,每当我读取字符或什么时减少它? – c2009l123 2009-11-19 00:03:28
您使用显式传递的缓冲区大小的方式可能会有所不同。您建议减少添加到缓冲区的字符数是可行的。另一种方法是在缓冲区中添加最大插入点之前计算,并检查该指针是否会保持小于当前插入指针。 – mjv 2009-11-19 00:10:32
我一直在想,为什么无法单独从指针确定缓冲区大小。它必须被某种东西知道或免费()不起作用。有没有技术上的原因,为什么不能有一个“int allocated_to(void * ptr)”函数?它只是标准C API中的漏洞之一吗? – Schwern 2009-11-19 07:32:07
其中一个可能的(慢)解决方案是允许函数处理NULL缓冲区指针并返回所需的缓冲区大小。然后调用它第二次与适当大小的缓冲区
标签是C,而不是C++。 – 2009-11-19 00:03:42
void ascii-morse (lookuptable *table, char* morse, char* ascii, int morse-size)
你有输出缓冲区的大小已经通过了,通过上面原型的外观。
ascii
无疑将是一个空值终止字符串,morse
将输出缓冲区:morse_size
(不morse-size
因为你拥有它,因为这不是一个有效的标识符)将是你被允许多少个字符来书写。
的伪代码将是这样的:
set apointer to start of ascii, mpointer to start of morse.
while apointer not at end of ascii:
get translation from lookuptable, using the character at apointer.
if length of translation is greater than morse_size:
return an error.
store translation to mpointer.
add 1 to apointer.
add length of translation to mpointer.
subtract length of translation from morse_size.
if morse_size is zero:
return an error.
store string terminator to mpointer.
你必须将其转换成C和实施查找功能,但是这应该是一个良好的开端。
指针用于从相关字符串中提取并插入相关字符串。对于每个字符,基本上都要检查输出缓冲区是否有足够的空间来添加莫尔斯电码段。最后,还需要检查字符串结束符'\0'
是否有足够的空间;
中,你是否有足够的空间方式是由你每一次循环增加morse
字符串的长度减少morse_size
变量。这样,morse_size
将始终是缓冲区中剩余的大小以供您使用。
哦,我想我得到它,但还有一件事,所以我会通过字符添加到莫尔斯char,因为这就是我如何翻译ascii莫尔斯。我怎么检查每次我想添加一个字符,有足够的内存?我的意思是,如果我通过“你好世界”缓冲区足够“hel”,我怎么知道我应该停在那里?我不应该每次减少缓冲区大小,我正在检查一个字符或类似的东西? – c2009l123 2009-11-19 00:12:54
查看最后一段。按照您要添加的莫尔斯码段的长度不断减少morse_size变量。当你得到一个3字符的莫尔斯电码段和morse_size时,只有两个(例如),你有一个错误条件。对于最后的字符串终止符也是如此。 – paxdiablo 2009-11-19 00:15:46
听起来像“缓冲区”有些混淆。没有缓冲区。 morse-size
告诉你有多少内存已分配给morse
(技术上,morse
指向的内存块)。如果莫尔斯大小是20,那么你有20个字节。这是19个字节的可用空间,因为字符串被空字节终止。你可以认为morse-size
是“字符串加上一个最大长度”。
您需要检查morse-size
以确保您没有写入比morse
更多的字节。 morse
只不过是一个指向内存中单个点的数字。不是一个范围,而是一个地方。之后分配给morse
的是什么。如果你把更多的信息写入morse
,你可能会冒险覆盖别人的记忆。 C不会为你检查这个,这是最高性能的价格。
它就像你去剧院的时候,引座告诉你“你可以坐A3和下5”,然后离开。你必须要有礼貌,不要坐6个席位,其他人得到A8。
诸如valgrind之类的工具对于发现C语言中的内存错误非常有用,并保持您的理智。
C中没有字符串吗?欢迎来到整个计算世界中最大的错误根源。
哇。“没有缓冲区”让我走遍了所有的形而上学,拉马斯的“没有勺子”:-) – paxdiablo 2009-11-19 00:18:47
“把目标字符串放在源头之前就是坏形式。” ????你认为标准库函数“不良形式”? – pmg 2009-11-19 00:21:03
@pmg既然你问了,是的。 :)我不是原生的C程序员,所以我的风格不是本地C语言。标准的C语言库约定是在30多年前计算世界是一个非常不同的地方。它们非常陈旧,与宇宙的其他部分不一致。我想这取决于你周围的代码遵循C约定的多少。就像,如果你投入巨资,你应该坚持到目标,来源。 – Schwern 2009-11-19 00:29:52
另一种解决方法是,不是传入要写入的预分配目标字符串,而是您的函数执行分配并返回指向它的指针。这是更安全的,因为调用者不必猜测你的函数需要多少内存。
char *ascii2morse(const char *ascii, lookuptable *table)
您仍然必须为摩斯电码分配足够的内存。由于摩尔斯电码不是固定长度,所以有两种策略。首先是简单地计算给定长度字符串(最长Morse序列* ascii中的字符数)所需的最大可能内存并分配该内存。这可能看起来很浪费,但它的调用者必须为你的原始计划做些什么。
另一种方法是使用realloc
在需要时继续增加字符串。你计算出需要多少字节来编码下一个字符,重新分配这些字节并将其附加到字符串中。这可能会比较慢,内存分配器现在非常复杂,但它会使用尽可能多的内存。
避免陷阱用户必须预先分配未知量的内存,同时消除不必要的“用户没有分配足够的内存”错误条件。
如果你真的想要节省内存,我会将每个点/破折号存储在莫尔斯码中作为2位而不是8位。你有三个“单词”,短信和长信。这是至少2位的空间。
做得很好,实际上将这个问题标记为作业开始。 :) – Noldorin 2009-11-19 00:45:04