C中的缓冲区大小

问题描述:

当以C语言提供缓冲区大小时,我怎么知道剩下多少以及何时需要停止使用内存?C中的缓冲区大小

例如,如果我写的功能是这样的:

void ascii_morse (lookuptable *table, char* morse, char* ascii, int morse_size) { 

} 

在这个应用程序,我将传递一个字符串(ASCII),我会把它转换成使用一些其他功能,每个ASCII转换为莫尔斯字符莫尔斯。我面临的问题是如何确保我不超过缓冲区大小。我甚至不知道何时使用缓冲区大小,或者我每次使用缓冲区大小时都会减少缓冲区大小。

当然的输出将是莫尔斯(所以我会添加字符串莫尔斯,但我想我知道如何做到这一点,它只是缓冲区的大小是什么,是很难理解我)

如果您需要更多的信息来了解问题,请告诉我,我尽力解释它。

+2

做得很好,实际上将这个问题标记为作业开始。 :) – Noldorin 2009-11-19 00:45:04

您需要将缓冲区大小和指针一起传递。

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; 
} 
+0

所以例如,如果我通过了一个10的缓冲区大小和字符串是“你好世界”我说缓冲区大小 - 每次我阅读的字符? – c2009l123 2009-11-19 00:02:37

+0

不,由于C中的字符串以空字节结尾,因此您可以使用'strlen'来获取长度。担心缓冲区大小适用于您要写入的字符串。 – Schwern 2009-11-19 00:08:27

+0

morse_size是结果的大小。你必须计算你输入'莫尔斯'时有多少个字符,并在morse_size -1时停止(因为你想为nul终止符保留最后一个字符)。当你阅读'ascii'中的字符时,你只是阅读,直到结束,这将是nul字符。 – nos 2009-11-19 00:10:27

缓冲区的大小不能推断单独的指针。它需要作为参数传递,或者以某种方式知道(如从DEFINE值或其他常量)或隐式知道...(后者,如果大小以某种方式改变但是这种改变是隐含的方法是“危险的”没有反映在使用缓冲区的地方......)

或者,更典型地在输入缓冲区(函数将读取的缓冲区)的情况下,缓冲区的末端可以用特殊标记字符或这样的字符序列。

+0

它已通过,但我如何使用它,每当我读取字符或什么时减少它? – c2009l123 2009-11-19 00:03:28

+0

您使用显式传递的缓冲区大小的方式可能会有所不同。您建议减少添加到缓冲区的字符数是可行的。另一种方法是在缓冲区中添加最大插入点之前计算,并检查该指针是否会保持小于当前插入指针。 – mjv 2009-11-19 00:10:32

+0

我一直在想,为什么无法单独从指针确定缓冲区大小。它必须被某种东西知道或免费()不起作用。有没有技术上的原因,为什么不能有一个“int allocated_to(void * ptr)”函数?它只是标准C API中的漏洞之一吗? – Schwern 2009-11-19 07:32:07

其中一个可能的(慢)解决方案是允许函数处理NULL缓冲区指针并返回所需的缓冲区大小。然后调用它第二次与适当大小的缓冲区

+0

标签是C,而不是C++。 – 2009-11-19 00:03:42

void ascii-morse (lookuptable *table, char* morse, char* ascii, int morse-size) 

你有输出缓冲区的大小已经通过了,通过上面原型的外观。

ascii无疑将是一个空值终止字符串,morse将输出缓冲区:morse_sizemorse-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将始终是缓冲区中剩余的大小以供您使用。

+0

哦,我想我得到它,但还有一件事,所以我会通过字符添加到莫尔斯char,因为这就是我如何翻译ascii莫尔斯。我怎么检查每次我想添加一个字符,有足够的内存?我的意思是,如果我通过“你好世界”缓冲区足够“hel”,我怎么知道我应该停在那里?我不应该每次减少缓冲区大小,我正在检查一个字符或类似的东西? – c2009l123 2009-11-19 00:12:54

+0

查看最后一段。按照您要添加的莫尔斯码段的长度不断减少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中没有字符串吗?欢迎来到整个计算世界中最大的错误根源。

+0

哇。“没有缓冲区”让我走遍了所有的形而上学,拉马斯的“没有勺子”:-) – paxdiablo 2009-11-19 00:18:47

+0

“把目标字符串放在源头之前就是坏形式。” ????你认为标准库函数“不良形式”? – pmg 2009-11-19 00:21:03

+1

@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位的空间。

+0

但是现在您与API消费者签有合约来释放该内存。可行,但丑陋而且相当危险。 – rpj 2009-11-19 02:53:10

+0

@rpj调用者不能释放它吗? – Schwern 2009-11-19 07:28:18