在C中,文字字符串地址是否总是大于任何分配的字符串地址?

时间:2012-04-20 04:40:53

标签: c string memory-management

我正在尝试区分文字字符串与已分配的字符串,因此我不小心尝试释放()文字字符串,这会导致段错误。

我可能尝试free()文字字符串的原因涉及一个可以嵌入的strcat()包装器:strcatex("My name ", strcatex("is ", strMyName));

无论原因如何,请考虑:

void* mallocex(int intBytes) 
{
    void* newPtr;

    newPtr = malloc(intBytes);

    if(newPtr == 0)
        return 0;
    else if(newPtr > maxPointer)
        maxPointer = newPtr;

    return newPtr;
}

int SafeFree(void **ptr)
{
    if((unsigned long) ptr > (unsigned long) maxPointer) 
        return 0;
    else
        free(*ptr);

    return 1;
}

使用示例:

char *newString;
newString = (char*) mallocex(12);

strcpy(newString, "Example one");

SafeFree(&newString);
SafeFree("Example two");

无论我的堆有多大,这总是有效吗?

4 个答案:

答案 0 :(得分:5)

没有这样的保证不依赖它。
字符串文字在只读实现定义区域的某处分配内存,无法以可移植的方式知道它将是什么,因此您不应对其做出任何假设。

答案 1 :(得分:1)

情况甚至比你想象的还要“糟糕”。比较仅针对指向同一对象(或仅指向超出的字节)的指针。因此,通常对于两个不同的对象(无论是静态分配为字符串文字还是动态地使用malloc左右),您甚至无法询问其中一个地址是否小于另一个。在大多数平台上,这样的比较是有效的,但严格来说你不能依赖它。

答案 2 :(得分:0)

不仅没有保证,相反的系统也很常见。在MacOS(我的笔记本电脑)上,例如:

#include <stdio.h>
#include <stdlib.h>

void pr_addr(const char *name, void *addr) {
    printf("%s: %p\n", name, addr);
}

int main(void) {
    pr_addr("literal", "literal");
    pr_addr("heap", malloc(10));
    return 0;
}
$ cc -o foo -W -Wall -O foo.c
$ ./foo
literal: 0x1ff1
heap: 0x100160

所以rodata部分在malloc竞技场的开头下面,与你在系统上看到的相反。

通常,具有精美分割或其他结构化指针类型的系统是您在非相邻对象之间进行无意义比较的地方。 p < q的测试通常编译为仅对段内偏移进行比较。例如,如果pq都指向其(不同)段的开头,则即使地址不同,它们的偏移也都为零。因此,p < qp > q都是假的,但p != q

答案 3 :(得分:0)

为了好玩,我写了一个尝试根据其他文字的地址进行猜测的尝试。它的工作原理是将潜在文字的地址与另一个已知文字,堆栈地址和堆地址进行比较。如果潜在地址比其他地址更接近文字,则假定潜在地址是文字。它在实践中可能不可靠。这是一个简单的版本:

int is_literal_simplistic(char *s) {
    char *literal = "literal";
    char stack[] = "stack";
    char *heap = malloc(1);
    free(heap);
    unsigned long literal_delta = labs(literal - s);
    unsigned long stack_delta = labs(stack - s);
    unsigned long heap_delta = labs(heap - s);
    return (literal_delta < stack_delta && literal_delta < heap_delta);
}

这里是更简洁的版本。它可能更简单:

int is_literal(char *s) {
  char *heap = malloc(1);
  free(heap);
  unsigned long literal_delta = labs("literal" - s);
  unsigned long stack_delta = labs((char *)&s - s);
  unsigned long heap_delta = labs(heap - s);
  return (literal_delta < stack_delta && literal_delta < heap_delta);
}

完全可运行的测试:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

//#define DEBUG

#ifdef DEBUG
void debug_literal(unsigned long literal,
                   unsigned long stack,
                   unsigned long heap,
                   unsigned long literal_delta,
                   unsigned long stack_delta,
                   unsigned long heap_delta) {
  printf("literal(%lx)  stack(%lx)  heap(%lx)\n", literal, stack, heap);
  printf("literal(%lu)  stack(%lu)  heap(%lu)\n", literal_delta, stack_delta, heap_delta);
  int answer = (literal_delta < stack_delta && literal_delta < heap_delta);
  printf("\t%s\n", answer ? "literal" : "other");
}
#else
void debug_literal(unsigned long literal,
                   unsigned long stack,
                   unsigned long heap,
                   unsigned long literal_delta,
                   unsigned long stack_delta,
                   unsigned long heap_delta) {
}
#endif

int is_literal_simplistic(char *s) {
    char *literal = "literal";
    char stack[] = "stack";
    char *heap = malloc(1);
    free(heap);
    unsigned long literal_delta = labs(literal - s);
    unsigned long stack_delta = labs(stack - s);
    unsigned long heap_delta = labs(heap - s);
    debug_literal((unsigned long)literal, (unsigned long)stack, (unsigned long)heap,
                  literal_delta, stack_delta, heap_delta);
    return (literal_delta < stack_delta && literal_delta < heap_delta);
}

int is_literal(char *s) {
  char *heap = malloc(1);
  free(heap);
  unsigned long literal_delta = labs("literal" - s);
  unsigned long stack_delta = labs((char *)&s - s);
  unsigned long heap_delta = labs(heap - s);
  debug_literal(0,0,0, literal_delta, stack_delta, heap_delta);
  return (literal_delta < stack_delta && literal_delta < heap_delta);
}

void test_literal_function(int(*liternal_fn)(char *)) {
  char *literal = "literal_test";
  char stack[] = "stack_test";
  char *heap = malloc(40);

  printf("\t%s\n", liternal_fn(literal) ? "literal" : "other");
  printf("\t%s\n", liternal_fn(stack) ? "literal" : "other");
  printf("\t%s\n", liternal_fn(heap) ? "literal" : "other");
  printf("\n");

  free(heap);
}

int main() {
  test_literal_function(is_literal_simplistic);
  test_literal_function(is_literal);

  return 0;
}