2012-09-03 60 views
1

下面是我的C代码:为什么我的变量从函数返回后会损坏?

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

char *username; 
char *password; 

void set_credentials(char*, char*); 

int main(void) 
{ 
    set_credentials(); 
    printf("%s\n", username);  //look here 3 
    printf("%s\n", password);  //look here 4 
    return EXIT_SUCCESS; 
} 

void set_credentials(char *username, char *password) 
{ 
    char c; 
    char lines[2][100]; 
    char * tmp = * lines; 
    char * user = "user"; 
    int i = 0; 
    FILE *fp = fopen("/netnfork/config/netnfork_credentials.properties", "r"); 

    if (fp == NULL) 
    exit(EIO); 
    while ((c = fgetc(fp)) != EOF) 
    { 
    if (c != '\n') 
    { 
     *tmp = c; 
     tmp++; 
    } else { 
     *tmp = '\0'; 
     i++; 
     tmp = lines[i]; 
    } 
    } 
    fclose(fp); 
    i = 0; 
    while (i < 2) 
    { 
    if (strncmp(user, lines[i], 4) == 0) 
    { 
     username = lines[i] + 5; 
     printf("%s\n", username); //look here 1 
    } else { 
     password = lines[i] + 9; 
     printf("%s\n", password); //look here 2 
    } 
    i++; 
    } 
} 

现在,当我运行代码,我得到这个:

MYNAME // //为1
输入mypassword 2
MYNAME // for 3
mypasswo // for 4

我不明白为什么那样的行为。有没有人对此有何认识?

+8

uswername /密码,点被分配在栈上,并销毁当'set_credentials'函数返回 – Gir

+0

不,他们没有,他们是全局变量的变量。 – Eregrith

+1

指针是全局的。他们指的是不是 – Gir

回答

1

这是一个使用malloc()和free()的版本。

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


/* "user " */ 
#define USERLINE_PREFIX 5 
/* "password " */ 
#define PASSLINE_PREFIX 9 



void set_credentials(char**, char**); 

int main(void) 
{ 
    /* to point to the username and password obtained from a text file */ 
    char *username = NULL; 
    char *password = NULL; 
    set_credentials(&username,&password); 
    /* (original scheme) printf("username: %s\n", username); */ 
    /* (original scheme) printf("password: %s\n", password); */ 
    printf("username: %s\n", username + USERLINE_PREFIX); // line starts "user "  
    printf("password: %s\n", password + PASSLINE_PREFIX); // line starts "password " 
    /* (original scheme) free(username - USERLINE_PREFIX); */ 
    /* (original scheme) free(password - PASSLINE_PREFIX); */ 
    free(password); 
    free(username); 
    return EXIT_SUCCESS; 
} 

void set_credentials(char **username, char **password) 
{ 
    /* file format: 
    line 1 ->user <username> 
    line 2 ->password <password> 
    */ 
    char c; 
    #define FILE_LINES 2 
    #define MAX_LINE_LENGTH 100 
    int i = 0, j = 0; 
    char *lines[FILE_LINES]; 
    char *tmp = NULL; 
    char *user = "user "; 
    char *pass = "password "; 
    char user_found = 0, password_found = 0; 
    for (j = 0; j < FILE_LINES; j++) 
    { 
    lines[j] = malloc(MAX_LINE_LENGTH + 1); 
    lines[j][0] = '\0'; 
    } 
    tmp = lines[0]; 
    const char *filename = "/netnfork/config/netnfork_credentials.properties"; 
    FILE *fp = fopen(filename, "r"); 

    if (fp == NULL) 
    { 
    printf("ERROR %d trying to open %s\n",errno,filename); 
    /* if not exiting program, would need to free() here */ 
    exit(EIO); 
    } 
           /* in case more lines than expected */ 
    while ((c = fgetc(fp)) != EOF && i < FILE_LINES) 
    { 
    if (c != '\n') 
    { 
     *tmp = c; 
     tmp++; 
    } else { 
     *tmp = '\0'; 
     i++; 
     tmp = lines[i]; 
    } 
    } 
    if (i < 2) { 
    printf("ERROR: file %s is incomplete needs %d lines (password and user)\n",filename,FILE_LINES); 
    /* if not exiting program, would need to free() here */ 
    exit(1); 
    } 
    fclose(fp); 
    i = 0; 
    while (i < FILE_LINES) 
    { 
    if (strncmp(user, lines[i], USERLINE_PREFIX) == 0) 
    { 
     user_found = 1; 
     /* (original scheme) *username = lines[i] + USERLINE_PREFIX; */ 
     *username = lines[i]; 
    } 
    else if (strncmp (pass, lines[i],PASSLINE_PREFIX) == 0) { 
     password_found = 1; 
     /* (original scheme) *password = lines[i] + PASSLINE_PREFIX; */ 
     *password = lines[i]; 
    } 
    else { 
     printf("ERROR: invalid line in file:\n"); 
     printf("%s\n",lines[i]); 
     /* if not exiting program, would need to free() here */ 
     exit(1); 
    } 
    i++; 
    } 
    /* check for the extremely unlikely event that the two lines are both of the same type */ 
    if (! (password_found && user_found)) 
    { 
    printf("ERROR: file %s is invalid, missing %s line\n",filename, (user_found) ? "password" : "user"); 
    /* if not exiting program, would need to free() here */ 
    exit(1); 
    } 
} 
+0

我认为这是最好的。 – artaxerxe

+0

我刚刚阅读了一些与'free()'函数相关的文档,在这里我有一个误解:当你在一个指针上调用'free()'时,它(''free'')会重用整个内存分配给该指针(通过'malloc')。所以,这样做:'免费(用户名 - USERLINE_PREFIX);',它不会使存储在'username'中的数据变得不可靠吗? – artaxerxe

+0

@artaxerxe此代码的问题是实际的字符数组是“user my_userid \ 0 .....................(最多101字节)”。但函数不会返回指向行首的指针,它会返回指向行中第6个字符的指针。因此,如果free()将处理所有内存malloc()ed,则必须给它一个小于“char *”当前指向的地址。我将更改代码以返回一个指向开始的指针(然后必须修改main以从第6个字符开始),这样free就可以工作,而不需要指针算术。 – Scooter

1

您已经创建了两个指针usernamepassword,指向在该特定功能堆栈框架上创建的局部变量。当函数返回时,这些指针将指向垃圾,因为堆栈框架已被销毁,所以函数局部变量。

您需要将变量作为参数传递给您的set_credentials函数,或者您需要创建一个struct,您可以从正确填充的函数中返回。按值返回结构体。不需要指针。

+0

如果你看看我的问题,它会被'username'和'password'修改为'set_credentials'的参数。但它运行时出错:'分段错误(核心转储)' – artaxerxe

2

您的问题是您正在为lines阵列的某些部分分配用户名和密码。 lines数组是一个局部变量,在set_credentials完成后分配给它的内存不再安全。要修复它,请使用malloc获取您的用户名和密码的内存,或使lines为全局变量,如usernamepassword

1

David发现你的问题。一种解决方案是分配函数可以填充的两个字符数组。

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



void set_credentials(char*, char*); 

int main(void) 
{ 
    /* to hold the username and password obtained from a text file */ 
    char username[200] = { '\0' }; 
    char password[200] = { '\0' }; 
    set_credentials(username,password); 
    printf("%s\n", username);  //look here 3 
    printf("%s\n", password);  //look here 4 
    return EXIT_SUCCESS; 
} 

void set_credentials(char *username, char *password) 
{ 
    char c; 
    char lines[2][100]; 
    int i = 0; 
    char *tmp = *lines; 
    char *user = "user"; 
    char *pass = "password"; 


    const char *filename = "/netnfork/config/netnfork_credentials.properties"; 
    FILE *fp = fopen(filename, "r"); 

    if (fp == NULL) 
    exit(EIO); 
    else 
    printf("successfully opened %s\n",filename); 
           /* in case more than 2 lines */ 
           /* or increase array first dimension */ 
    while ((c = fgetc(fp)) != EOF && i < 2) 
    { 
    if (c != '\n') 
    { 
     *tmp = c; 
     tmp++; 
    } else { 
     *tmp = '\0'; 
     i++; 
     tmp = lines[i]; 
    } 
    } 

    fclose(fp); 
    i = 0; 
    while (i < 2) 
    { 
    if (strncmp(user, lines[i], 4) == 0) 
    { 
     strcpy(username,lines[i] + 5); 
    } 
    else if (strncmp (pass, lines[i],8) == 0) { 
     strcpy(password,lines[i] + 9); 
    } 
    else { 
     /* can't assume file is correct so fatal error if not */ 
     printf("ERROR: invalid line in file:\n"); 
     printf("%s\n",lines[i]); 
     exit(1); 
    } 
    i++; 
    } 
} 
+0

感谢您的明确回答!无论如何,就像一个案例研究一样,只有通过指针(当然没有全局变量),才有可能在没有拷贝('strcpy'函数)的情况下实现这个功能。我来自'Java',这个问题使我困惑不已。我只想看看'C'中局部变量的真实行为。 – artaxerxe

1

你可以允许你返回一个指向它的函数使用一个静态变量,因为一个静态变量将围绕功能已经结束,也。

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


/* 
    In order to modify a caller's char in a function it must be passed as pointer to char 
    In order to modify a caller's "char *" in a function it must be passed as pointer to "char *" 
*/ 
void set_credentials(char**, char**); 

int main(void) 
{ 
    /* to point to the username and password obtained from a text file */ 
    char *username = NULL; 
    char *password = NULL; 
    /* pass the addresses of the char *'s so their contents can be modified */ 
    set_credentials(&username,&password); 
    printf("%s\n", username);  //look here 3 
    printf("%s\n", password);  //look here 4 
    return EXIT_SUCCESS; 
} 

void set_credentials(char **username, char **password) 
{ 
    char c; 
#define MAX_FILE_LINES 2 
    static char lines[MAX_FILE_LINES][100]; 
    int i = 0; 
    char *tmp = *lines; 
    char *user = "user"; 
    char *pass = "password"; 


    const char *filename = "/netnfork/config/netnfork_credentials.properties"; 
    FILE *fp = fopen(filename, "r"); 

    if (fp == NULL) 
    { 
    printf("ERROR: unable to open %s\n",filename); 
    exit(EIO); 
    } 
    else 
    printf("successfully opened %s\n",filename); 
           /* in case more lines than expected */ 
    while ((c = fgetc(fp)) != EOF && i < MAX_FILE_LINES) 
    { 
    if (c != '\n') 
    { 
     *tmp = c; 
     tmp++; 
    } else { 
     *tmp = '\0'; 
     i++; 
     tmp = lines[i]; 
    } 
    } 

    fclose(fp); 
    i = 0; 
    while (i < 2) 
    { 
    if (strncmp(user, lines[i], 4) == 0) 
    { 
     /* assign to the char * back in the calling routine */ 
     *username = lines[i] + 5; 
    } 
    else if (strncmp (pass, lines[i],8) == 0) { 
     /* assign to the char * back in the calling routine */ 
     *password = lines[i] + 9; 
    } 
    else { 
     /* can't assume file is correct so fatal error if not */ 
     printf("ERROR: invalid line in file:\n"); 
     printf("%s\n",lines[i]); 
     exit(1); 
    } 
    i++; 
    } 
} 
+0

这就是我一直在寻找的解决方案。现在我想(至少我希望)能够理解'C'中的自动变量是如何工作的。 :) – artaxerxe

相关问题