与char *和asprintf联合

时间:2014-08-21 14:21:01

标签: c

我正在尝试学习C并希望使用union。虽然我没有使用char *,但我看起来很顺利,但是我不会认为它会有所作为。

以下是我的工会宣布的方式:

union MyData
{
    char * targetNumber;
    int callResult;
} myData;

下面是我的主要功能,它使用我的联合并尝试存储然后从联合中读取

int main(int argc, char** argv) 
{

    union MyData myData;

    asprintf(&myData.targetNumber, "My Target Number");
    myData.callResult = 1;

    printf("Target Number: %s\n", myData.targetNumber);
    printf("Call Result: %i\n", myData.callResult);

    return (EXIT_SUCCESS);
}

当我通过gdb它看起来像asprintf工作,但是当设置callResult时,targetNumber变得越界,所以当我尝试printf它时,它会段错误。我尝试使用strdup而不是asprintf,但没有喜悦。

感谢您提供的任何帮助。

4 个答案:

答案 0 :(得分:3)

错误是您应该使用struct而不是union。您希望同时使用targetNumbercallResult,而不是其中任何一个,因此存储它们的正确数据结构是struct。使用union,它们存储在相同的内存位置。因此,写入一个会导致另一个的价值丢失。

此外,虽然不太可能,但asprintf()可能会失败。您应该针对负值测试返回的int

注意:对于你用它做什么,asprintf(&myData.targetNumber, "My Target Number");也可以写成myData.targetNumber = "My Target Number";但我知道这可能是为了调试而减少的代码。

答案 1 :(得分:3)

我认为您混淆了unionstruct之间的区别。如果您想将targetNumbercallResult分组到一个结构中,您可以执行以下操作:

struct MyData
{
    char * targetNumber;
    int callResult;
} myData;

然后你的代码应该可以工作。

当您将MyData定义为union时,您基本上创建的类型可以用作targetNumbercallResult,但不能同时用作两者,因为它们在记忆中占据相同的空间。

让我们假设sizeof(union MyData) == sizeof(targetNumber) == sizeof(int) == 4,然后当您声明myData时,myData将被初始化为零(0x00000000)。

union MyData myData; // 0x00000000

由于myData归零,myData.targetNumber也将归零,这也是NULL指针。 asprintf()将分配一个新字符串并填充其内容和 将其分配给myData.targetNumber。通话结束后,myData.targetNumber会指向内存中的某个位置(例如0x12345678)。

asprintf(&myData.targetNumber, "My Target Number");

现在,您将myData.callResult覆盖为10x00000001)。由于myData是一个联合,因此会产生myData.callResult == myData.targentNumber == 1。您刚刚丢失了指向已分配字符串的指针,因为myData.targetNumber不再是0x12345678而是0x00000001

myData.callResult = 1;

这将导致您的段错误。由于myData.targetNumber == 0x000000010x00000001不是有效指针(至少不是指向字符串的有效指针),因此可能会以段错误结束。

printf("Target Number: %s\n", myData.targetNumber);

如果你要到这里,myData.callResult将正常打印。

printf("Call Result: %i\n", myData.callResult);

答案 2 :(得分:1)

union在内存中使用相同的空间。所以一旦你设置了callResult,targetNumber就变成了0x1。因此你丢失了你的字符串,而新的地址很低,应该导致seg错误。

UPDATE:union应该用于字节修改情况。在通用数据管理中,它没有struct那么有用。

答案 3 :(得分:0)

您不能将char *用作字符数组。它只是一个变量来保存一个(或多个)字符的地址。

  1. 您必须在取消引用之前对其进行初始化。 (使用指向的值)
  2. 您必须在asprintf()调用中分配空间来保存要复制的字符。
  3. 当您编写myData.callResult = 1时,您正在覆盖(使其无法使用)存储在联合的myData.targetNumber部分中的值(两个字段共享相同的存储空间)
  4. 要为联盟分配数据,您必须使用以下内容:

    union MyData {
        char targetNumber[100]; /* allocate space for 100 characters */
        int callResult; /* space for an integer is shared with the 100 characters of targetNumber */
    } myData;
    

    如果您想同时使用这两个字段,则无法共享相同的空间,而是需要struct,如:

    struct MyData {
        char targetNumber[100]; /* allocate space for 100 characters */
        int callResult; /* space for an integer is shared with the 100 characters of targetNumber */
    } myData;
    

    尝试在两种情况下都打印sizeof myData,您将看到分配的存储资源的差异。 (第一个为联合中最长的字段分配空间,而第二个为两个字段分配空间)