我正在做一个需要打印指针内存(地址)的练习。 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 ........$
答案 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 */