如何在没有printf的情况下打印指针地址

时间:2018-01-02 18:54:49

标签: c arrays pointers printf

我正在做一个需要打印指针内存(地址)的练习。 printf("%p", ..)很容易做到这一点,但我不允许使用它。

您知道如何在不使用printf()的情况下获取地址吗? 我唯一可以使用的功能就是写#39;

以下是我的演习陈述:

编写一个带(const void *addr, size_t size)的函数,并显示 内存如示例中所示。 您的函数必须声明如下:

void print_memory(const void *addr, size_t size);
$ cat main.c

void  print_memory(const void *addr, size_t size);

int   main(void)
{    
      int tab[10] = {0, 23, 150, 255,
                     12, 16,  21, 42};

      print_memory(tab, sizeof(tab));
      return (0);
}

$ gcc -Wall -Wall -Werror main.c print_memory.c && ./a.out | cat -e
0000 0000 1700 0000 9600 0000 ff00 0000 ................$
0c00 0000 1000 0000 1500 0000 2a00 0000 ............*...$
0000 0000 0000 0000                     ........$

4 个答案:

答案 0 :(得分:3)

编辑:我在OP澄清他们实际想要转储内存内容之前提供了这个答案(在澄清之前他们要求代码行为像printf("%p", mem_ptr)

此代码应拼出每个数字(十六进制):

#include <stdint.h>

/* you must provide this function somewhere */
extern void write_char(char);

char hex_digit(int v) {
    if (v >= 0 && v < 10)
        return '0' + v;
    else
        return 'a' + v - 10; // <-- Here
}

void print_address_hex(void* p0) {
    int i;
    uintptr_t p = (uintptr_t)p0;

    write_char('0'); write_char('x');
    for(i = (sizeof(p) << 3) - 4; i>=0; i -= 4) {
        write_char(hex_digit((p >> i) & 0xf));
    }
}

此处,print_address_hex是一次打印一个数字(like this one)的基本算法。 [简化我并不关心领先零的事情]

算法的核心是运算符>>(类似二进制整数除法)和&(类似二进制余数)。 [请注意,这些操作员一般仅适用于基础2,4,8,16,2 n]。

我使用uintptr_t使其可移植。此类型 - 在<stdint.h>中声明 - 指的是能够保存指针的整数类型(与架构无关)。我们需要一个整数类型,以便我们可以使用算术运算符(除+-之外,它是指针运算的唯一有效运算符。)

答案 1 :(得分:2)

您可以尝试:

#include <stdio.h>

void print_memory(const void *addr, size_t size)
{
    size_t printed = 0;
    size_t i;
    const unsigned char* pc = addr;
    for (i=0; i<size; ++i)
    {
        int  g;
        g = (*(pc+i) >> 4) & 0xf;
        g += g >= 10 ? 'a'-10 : '0';
        putchar(g);
        printed++;

        g = *(pc+i) & 0xf;
        g += g >= 10 ? 'a'-10 : '0';
        putchar(g);
        printed++;
        if (printed % 32 == 0) putchar('\n');
        else if (printed % 4 == 0) putchar(' ');
    }
}

int main(void) {
int tab[10] = {0, 23, 150, 255, 12, 16, 21, 42};

print_memory(tab, sizeof(tab)); return (0);

    return 0;
}

<强>输出

0000 0000 1700 0000 9600 0000 ff00 0000 
0c00 0000 1000 0000 1500 0000 2a00 0000 
0000 0000 0000 0000 

答案 2 :(得分:1)

您不必打印内存,您必须以十六进制转换addr中的每个字节并打印它,第二部分用点和星号转换char中每个字节的值,如果它不可打印它会打印点。

#include <string.h>

#include <unistd.h>

void    ft_putchar(char c)
{
    write(1, &c, 1);
}

void    print_ascii(const char *addr, int i)
{
    int j;
    int len;

    j = 0;
    if ((i + 1) % 16 == 0)
        len = 16;
    else
        len = (i + 1) % 16;
    while (j < 16 - len)
    {
        ft_putchar(' ');
        ft_putchar(' ');
        if (j % 2)
            ft_putchar(' ');
        j++;
    }
    if ((16 - len) % 2)
        ft_putchar(' ');
    j = 0;
    while (j < len)
    {
        if (*(addr + i / 16 * 16 + j) >= 32 && *(addr + i / 16 * 16 + j) <= 126)
            ft_putchar(*(addr + i / 16 * 16 + j));
        else
            ft_putchar('.');
        j++;
    }
    ft_putchar('\n');
}

void    print_hex(unsigned char value, int index)
{
    if (index < 2)
    {
        print_hex(value / 16, index + 1);
        if (value % 16 >= 10)
            ft_putchar('a' + value % 16 % 10);
        else
            ft_putchar('0' + value % 16);
    }
}

void    print_memory(const void *addr, size_t size)
{
    char    *ptr;
    size_t  i;

    if (addr && size > 0)
    {
        ptr = (char*)addr;
        i = 0;
        while (i < size)
        {
            print_hex(*(ptr + i), 0);
            if (i % 2)
                ft_putchar(' ');
            if ((i + 1) % 16 == 0 || (i + 1) == size)
                print_ascii(addr, i);
            i++;
        }
    }
}

此代码适用于您的考试。

答案 3 :(得分:0)

你可以这样做......你说printf()是不受限制的,但是你对sprintf一无所知。

 print_bytes(char *ptr, int count)
 {
   int i;
   char string[1024];
   string[0] = 0;
   for(i = 0; i < count; i++)
   {
     sprintf(string,"%s %2x", string, *(ptr+i));
   }
   puts(string);
 }

这应该循环遍历count字节,从ptr中的传入地址开始打印出每个十六进制字节。

显然,这并没有尝试正确调整字符串数组的大小。应根据传入的计数动态调整大小。

要将write()替换为puts(),您可以使用:

 write(1, string, strlen(string)); /* 1 = STDOUT */