簡體   English   中英

從函數返回后,為什么我的變量損壞了?

[英]Why is my variable corrupt after returning from a function?

下面是我的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 // 3
mypasswo //為4

我不明白為什么會這樣。 有誰對這有什么想法?

您的問題是您要為lines數組的各個部分分配用戶名和密碼。 lines數組是一個局部變量,在set_credentials完成后,分配給它的內存不再安全。 要解決此問題,請使用malloc獲取您的用戶名和密碼的內存,或者使lines成為usernamepassword為的全局變量。

您已經創建了兩個指針usernamepassword ,它們指向在特定函數堆棧框架上創建的函數局部變量。 當函數返回時,這些指針將指向垃圾,因為堆棧幀已被破壞,因此函數的局部變量也是如此。

您需要將變量作為args傳遞給set_credentials函數,或者需要創建一個struct ,該struct可以從正確填充的函數中返回。 按值返回結構。 無需指針。

大衛確定了您的問題。 一種解決方案是分配該函數可以填充的兩個字符數組。

#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++;
  }
}

您可以在函數中使用靜態變量,該函數允許您返回指向它的指針,因為即使在函數退出后,靜態變量也會存在。

#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++;
  }
}

這是使用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);
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM