0

関数を使用して、構造体の一部である文字列の内容を変更したいと考えています。問題は、関数の外側に文字列を印刷すると出力がないことですが、関数の内側に印刷すると、出力は正しい出力である FOO になります。問題があると思われる行にコメントを追加しました。

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

#define ACCOUNT_NUM_LEN 15
#define NAME_LEN 255
#define PIN_LEN 4
#define BAL_LEN 50

typedef struct account
{
    // account  info
    int account_num[ACCOUNT_NUM_LEN];
    int pin[PIN_LEN];
    float bal;

    // name of the account owner
    char* fname;
    char* lname;

    // link to next account
    struct account *next;
}
account;

account* root;
int num_of_accounts;

bool init(void)
{
    // example
    char account_inf[80] = "FOO|BAZ|123123000012300|1234|5000.00";
    const char delimiter[2] = "|";

    // initialize root and set number of accounts to 0
    root = NULL;
    num_of_accounts = 0;

    // get the first token
    char* token = strtok(account_inf, delimiter);

    // create a new user each line
    account* new_user = malloc(sizeof(account));
    if (new_user == NULL)
        return false;

    // initialize new user info
    new_user->lname = NULL;
    new_user->fname = NULL;
    new_user->next = NULL;

    // walk through other tokens
    int info = 0;
    while (token != NULL)
    {
        // filter info
        if (info == 0)
        {
            new_user->lname = token; // problem
            info++;
        }
        else if (info == 1)
        {
            new_user->fname = token; // problem
            info++;
        }
        else if (info == 2)
        {
            for (int i = 0; i < ACCOUNT_NUM_LEN; i++)
                new_user->account_num[i] = token[i] - '0';
            info++;
        }
        else if (info == 3)
        {
            for (int i = 0; i < PIN_LEN; i++)
                new_user->pin[i] = token[i] - '0';
            info++;
        }
        else if (info == 4)
        {
            new_user->bal = atof(token);
            info++;
        }

        token = strtok(NULL, delimiter);
    }

    root = new_user;
    printf("%s\n", root->lname);
    printf("%s\n", root->fname);
    for (int i = 0; i < ACCOUNT_NUM_LEN; i++)
        printf("%d", root->account_num[i]);
    printf("\n");
    for (int i = 0; i < PIN_LEN; i++)
        printf("%d", root->pin[i]);
    printf("\n");
    printf("%f\n\n", root->bal);

    return true;
}

int main(void)
{
    // load up all accounts. exit if no account is found or made
    if (!init())
        return 1;

    printf("%s\n", root->lname);
    printf("%s\n", root->fname);
    for (int i = 0; i < ACCOUNT_NUM_LEN; i++)
        printf("%d", root->account_num[i]);
    printf("\n");
    for (int i = 0; i < PIN_LEN; i++)
        printf("%d", root->pin[i]);
    printf("\n");
    printf("%f\n\n", root->bal);

    return 0;
}
4

1 に答える 1

1

のマンページをstrtok読む必要があります。この関数は、元の文字列へのポインタを返します。入力文字列をスタックに割り当てるため、init関数から戻ると割り当てが解除されます。printfその後inを呼び出すとmain、スタック上の古い文字列が上書きされます。printfこれを説明するために、入力文字列の前に一連のパディングを追加して、呼び出しによって上書きされないようにすることができます。

bool init(void)
{
    // adding this padding should make the program print the desired output
    char padding[1024];
    // example
    char account_inf[80] = "FOO|BAZ|123123000012300|1234|5000.00";
    // . . .

ただし、スタックからポップされたメモリをまだ使用しているため、これは実際の修正ではありません。幸いなことに、実際に修正するために必要なのは、入力文字列をヒープに割り当てることだけです。

const char INPUT_STR[] = "FOO|BAZ|123123000012300|1234|5000.00";

bool init(void)
{
    // example
    char * account_inf = malloc(sizeof(INPUT_STR));
    strcpy(account_inf, INPUT_STR);
    // . . .

または、文字列を静的メモリに入れることもできます (つまり、取り外してそのまま使用します)。ただし、そうするとconst、静的メモリに格納されている元の文字列が変更されるため、再度使用することはできません。後で。INPUT_STRstrtok

于 2013-10-16T04:22:16.990 に答える