我正在尝试一个程序,其中使用malloc创建24字节的内存空间。想法是在12 byte频谱中的前10个字节中存储名称(字符串),并在其后的2个字节中存储年龄(int)。我希望对两组数据执行此操作,因此我分配了2 x 12 = 24字节。我想将空间用作异构2D数组。

下图说明了如何组织存储空间。

c++ - 将字符串后的int存储在动态分配的内存中时出错-LMLPHP

这是我的代码:

void* ptr = malloc(24);
string* st;
string t_string;
int i=0, c=1, t_int;
int* it;

while(i < 24){
    cout << "Enter name and age (" << (c++) << "): ";
    cin >> t_string >> t_int;
    st = (string*)(ptr) + i;
    *st = t_string;
    it = (int*)(ptr) + i + 10;
    *it = t_int;

    i+=12;
}

cout << endl;

i=0;
while(i < 24){
    st =  (string*)(ptr) + i;
    it = (int*)(ptr) + i + 10;
    cout << *st << " is " << *it << " years old.\n";

    i+= 12;
}


问题是当我输入两个名称和年龄时,第一个年龄总是显示错误。这是输出:

Enter name and age (1): Progyammer 19
Enter name and age (2): Coderguy00 19

Progyammer is 1629513069 years old.
Coderguy00 is 19 years old.


每次,只有第一个人的年龄才会发生。

为什么会发生这种情况,我该如何解决?

最佳答案

虽然您实际上应该在C中使用struct或在C ++中使用class,但是如果您在某些微控制器上限制了堆栈空间,那么每12字节块的额外4字节填充会有所不同,没有理由不能完全按照自己的意愿去做-但我建议您使用C而不是C ++来处理这类黑客。同样,如果您只是为一个学习项目执行此操作,处理通用数据块,了解严格的别名规则C11 Standard - §6.5 Expressions (p6)并了解有关在块中寻址的信息,那也很好。

首先,您将要创建类型为char的24字节分配内存块(请参见上面的6.5节表达式)。一旦为一个内存块分配/验证了存储空间,然后由您来创建逻辑来存储和访问该内存块中您希望的信息。 (您没有12个字节的块的数组,而只有24个字节的块,因此数组索引将对您没有好处,这是指针算术还是什么都不做。

所需的指针算法确实没有什么困难。您知道您将需要将每个12字节块视为一个存储区域。因此,遍历内存块可以使用(pointer + i * BLKSZ12)定位每个12字节块的开始。从那里开始,您知道short将从头开始存储另一个STRSZ(即10)字节。因此,在循环时,可以使用short存储或访问每个对应的pointer + i * BLKSZ12 + STRSZ。这只是从该偏移量存储或检索age的简单问题。

综上所述,您可以执行以下操作:

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

#define STRSZ 10
#define BLKSZ 12
#define BUFSZ 512

int main (void) {

    char *block,            /* pointer to generic block of memory */
        buf[BUFSZ] = "";    /* buffer for fgets use */
    size_t i = 0,           /* general loop var / counter */
        nblks = 2;          /* number of BLKSZ blocks to allocate */

    /* allocate block of nblks * BLKSZ bytes / validate */
    if (!(block = malloc (nblks * BLKSZ))) {
        perror ("malloc-block");
        exit (EXIT_FAILURE);
    }

    while (i < nblks) {     /* for each of the blocks */
        size_t len;         /* var for holding string length */
        printf ("\nenter name (9 char max): "); /* prompt/validate */
        if (!fgets (buf, BUFSZ, stdin)) {   /* read/validate input */
            fprintf (stderr, "warning: user canceled input.\n");
            exit (EXIT_FAILURE);
        }
        len = strlen (buf);                 /* get length */
        if (len && buf[len - 1] == '\n')    /* check trailing '\n' */
            buf[--len] = 0;                 /* overwrite w/nul-character */
        else if (len == BUFSZ - 1) {        /* check all input fit in buf */
            fprintf (stderr, "error input too long or buf.\n");
            continue;           /* go get next name */
        }
        if (len > STRSZ - 1) {  /* validate name fits */
            fprintf (stderr, "error: name exceeds %d chars.\n", STRSZ - 1);
            continue;
        }
        strcpy (block + i * BLKSZ, buf);
        printf ("enter age              : "); /* prompt/validate */
        if (!fgets (buf, BUFSZ, stdin)) {   /* read/validate input */
            fprintf (stderr, "warning: user canceled input.\n");
            exit (EXIT_FAILURE);
        }   /* convert age to short from buf */
        if (sscanf (buf, "%hd", (short*)(block + i * BLKSZ + STRSZ)) != 1) {
            fprintf (stderr, "error: conversion failed, block %zu.\n", i);
            continue;
        }
        i++;    /* we got a valid block, increment block count */
    }

    printf ("\nNames       Age\n");
    for (i = 0; i < nblks; i++) /* output info stored in each block */
        printf ("%-10s  %2hd yrs.\n", block + i * BLKSZ,
                *(short*)(block + i * BLKSZ + STRSZ));

    free (block);   /* free block */

    return 0;
}


使用/输出示例

$ ./bin/alloc_blk24

enter name (9 char max): Mary
enter age              : 25

enter name (9 char max): Joeseph
enter age              : 90

Names       Age
Mary        25 yrs.
Joeseph     90 yrs.


内存使用/错误检查

每当您在C中动态分配内存时,都取决于您是否已正确使用了该内存,没有内存错误并且已分配的所有内存都已释放。在Linux上,valgrind工具是首选工具。所有操作系统都有类似的工具。它们易于使用,您只需通过它们运行程序即可。

例如,使用valgrind可以确认仅分配了一个24字节的内存块,没有内存错误,并且在执行程序之前已正确释放了分配的所有内存,例如

valgrind ./bin/alloc_blk24
==26366== Memcheck, a memory error detector
==26366== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==26366== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==26366== Command: ./bin/alloc_blk24
==26366==

enter name (9 char max): Mary
enter age              : 25

enter name (9 char max): Joeseph
enter age              : 89

Names       Age
Mary        25 yrs.
Joeseph     89 yrs.
==26366==
==26366== HEAP SUMMARY:
==26366==     in use at exit: 0 bytes in 0 blocks
==26366==   total heap usage: 1 allocs, 1 frees, 24 bytes allocated
==26366==
==26366== All heap blocks were freed -- no leaks are possible
==26366==
==26366== For counts of detected and suppressed errors, rerun with: -v
==26366== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)


正如所有人所建议的那样(包括我在内),这不是您应该使用的方式来使用一块内存来保存两种不相关的数据类型(不在内存关键型硬件上,或者将其用于学习练习)。好的原因是,C出于讨论的原因提供了执行此操作所需的所有工具。 C将使您几乎可以在计算机上以闪电般的速度执行任何操作-无论您是否应该这样做-只是问题的另一方面。

如果您还有其他问题,请告诉我。

关于c++ - 将字符串后的int存储在动态分配的内存中时出错,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48678787/

10-15 00:55
查看更多