这个C代码如何打印正确的字符串?

时间:2015-03-21 09:42:28

标签: c

我的代码:

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

typedef struct island{
    char *name;
    struct island *previous;
} island;

void printIsland(island is){
    printf("%s\n", is.name);
    if(is.previous != NULL){
        printf("Previous island: %s", *(is.previous));
    }
}

int main(){

    // the file to be read.
    FILE *islandsFile = fopen("islands.txt","r");

    // temporary location to store the name read from the file.
    char name[40];

    // temporary pointer to an island which has been already read for linking.
    island *previousIsland = NULL;

    while(fscanf(islandsFile,"%s",name) != EOF){
        // allocate space for a new island and point to it with (*newIsland) pointer
        island *newIsland =malloc(sizeof(island));

        // assign name
        newIsland->name = strdup(name);
        newIsland->previous = previousIsland;
        // now previousIsland is the newIsland..
        previousIsland = newIsland;
        printIsland(*newIsland);
        puts("");
    }

    fclose(islandsFile);
}

文件是这样的:

islandone
islandtwo
islandthree

输出将是:

islandone
islandtwo
Previous island: islandone
islandthree
Previous island: islandtwo

但为什么

printf("Previous island: %s", *(is.previous))
打印岛名?你也可以打算我打算打印它,我不知道因为我不小心尝试了它。怎么打印岛屿的名字?

2 个答案:

答案 0 :(得分:2)

结构保证在内存中布局,在第一个元素之前没有填充。这意味着例如指向结构的指针和指向结构的第一个元素的指针是相同的。

printf没有能力实际检查传递给它的内容,但是相信格式字符串中的描述是参数列表的准确表示(NB。一个好的编译器会添加检查无论如何)。所以printf假设它收到的参数是char *并相应地解释它。

因为你实际传递的参数是一个char*处于领先位置的结构,所以该参数槽中的数据与 在该参数槽中的数据相同,如果你只传递了成员而不是整个结构。

在这种情况下,数据也跟随结构的其余部分的事实不会影响任何事情,因为 - 因为 - printf没有被格式字符串指示寻找更多的论点。确实传递了更多数据,并且字符串预期会有更多的参数,island的其余成员会阻碍并破坏参数列表。

这样做通常不安全,在处理指针时,实际上只应依赖struct first-element-layout规则,而不是依赖于值传递的结构。

答案 1 :(得分:1)

*(is.previous)是结构本身。结构按值传送到printf,即复制到堆栈上。结构的第一个字段是name指针,char*只是printf。由于printf是vararg,调用者会在调用后清除堆栈。

P.S。虽然*(is.previous)无意中有效,但代码必须更改为is.previous->name