2013-10-16 39 views
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|123123000|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; 
} 
+0

這是打印代碼的一個可怕的重複。你應該創建一個'dump_account()'函數,它有一個指向賬戶的指針並打印出詳細信息,然後使用它兩次。 'account_num'和'pin'的編碼也很有趣。我不擅長閱讀屏幕上的控制字符。 –

+0

@JonathanLeffler - 他正在打印賬戶#並使用'%d'進行銷售。控制角色從哪裏來? – DaoWen

+0

複製字符串時,應該使用'strcpy'。 –

回答

1

您應該閱讀manpage for strtok。該函數將指針轉換爲原始字符串。由於您在堆棧中分配了輸入字符串,因此當您從init函數返回時,它將被釋放。當您在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|123123000|1234|5000.00"; 
    // . . . 

然而,這不是一個真正的修復:爲了說明這一點,你可以在你輸入字符串的前面加了一堆填充所以它不會被printf電話覆蓋內存已被彈出堆棧。幸運的是,所有你需要做的真正解決它是堆分配的輸入字符串:

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

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

或者,你可以只是把靜態存儲器串(即採取const關閉INPUT_STR,只是使用) ,但如果你這樣做,那麼請記住strtok將修改存儲在靜態存儲器中的原始字符串,因此以後不能再使用它。

+0

目前還不清楚'strtok()'的手冊頁將討論返回指向局部變量的指針的業務。正在返回指向局部變量的分析是準確的。 1 KiB緩衝區是一個有趣的調整;另一種方法是使'account_inf'成爲一個靜態數組(具有確定性和可支持性)。 –

+0

@JonathanLeffler - 你說得對,我鏈接到不明確的手冊頁(儘管它在那裏)。我在我的Mac上閱讀了這個版本(一個BSD手冊頁),它更加明確。我將鏈接改爲了OpenGroup的聯機幫助頁面,該功能更清晰。至於使'account_inf'成爲一個靜態數組 - 這就是我在我的答案的最後一段中提出的建議。然而,我仍然認爲,將常量靜態字符串複製到堆內存中是一個更好的解決方案,因爲'strtok'破壞了它的第一個參數。 – DaoWen

+0

謝謝:D所以這只是一個範圍問題?非常感謝!我現在明白了。 –