Home > Mobile >  Passing a reference of a member in a struct to modify it
Passing a reference of a member in a struct to modify it

Time:09-12

I'm doing a program for a university project. currently I'm doing the user configuration for being able to change both the password and the user name. I was thinking a way to use a single function for both process instead of creating two separated ones.

My goal was to pass a reference to the struct that holds the user data, and a reference to the corresponding member of the struct I want to edit, both being a char[64]. So after I edit the member I can just rewrite the whole line in the file with the updated data.


void change_user_data(char *input, struct user ***logged_user,
                      char *data_to_alter, FILE **user_registry) {
  // making sure the returned input is valid.
  if (strcmp(input, "..."))
    return;

  struct user find_user;

  fseek(*user_registry, 0, SEEK_SET);
  while (!feof(*user_registry)) {
    fread(&find_user, sizeof(struct user), 1, *user_registry);

    if (0 != strcmp(find_user.user_name, (**logged_user)->user_name))
      continue;

    strcpy(data_to_alter, input);

    fseek(*user_registry, 0, SEEK_CUR - 1);
    fwrite((**logged_user), sizeof(struct user), 1, *user_registry);

    break;
  }
  return;
}

This is the function that should handle the change of both the struct and the file.


change_user_data(change_password(input), &logged_user, (*logged_user)->password, &user_id);

and here was my attempt to pass the arguments.

There was no error message, but there wasn't any change neither for the struct or the file. I guess that what is happening is that it's only creating a copy of the member, I tried to change the way I passed the member but none of them worked.

Minimal Reproductable Example:

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

#define MAXLEN 64

struct user {
  char user_name[MAXLEN];
  char password[MAXLEN];
};

void placeholder_function(struct user *logged_user);
void change_user_data(char *input, struct user **logged_user,
                      char *data_to_alter, FILE **user_registry);

int main() {
  struct user logged_user;

  placeholder_function(&logged_user);

  return 0;
}

void placeholder_function(struct user *logged_user) {
  FILE *user_registry;
  if (!(user_registry = fopen("user_registry.bin", "w b"))) {
    printf("Couldn't open file\n");
    exit(1);
  }
  strcpy(logged_user->user_name, "Admin\0");
  strcpy(logged_user->password, "Admin\0");

  fseek(user_registry, 0, SEEK_SET);
  fwrite(logged_user, sizeof(struct user), 1, user_registry);


  // expected output: Admin Admin
  printf("%s %s\n", logged_user->user_name, logged_user->password);

  // rest of program here...

  change_user_data("1234\0", &logged_user, logged_user->password,
                   &user_registry);

  printf("%s %s\n", logged_user->user_name, logged_user->password);
  // wanted output: Admin 1234
}

void change_user_data(char *input, struct user **logged_user,
                      char *data_to_alter, FILE **user_registry) {
  struct user find_user;

  fseek(*user_registry, 0, SEEK_SET);
  while (!feof(*user_registry)) {
    fread(&find_user, sizeof(struct user), 1, *user_registry);

    if (0 != strcmp(find_user.user_name, (*logged_user)->user_name))
      continue;

    strcpy(data_to_alter, input);

    fseek(*user_registry, 0, SEEK_CUR - 1);
    fwrite((*logged_user), sizeof(struct user), 1, *user_registry);

    break;
  }
}

CodePudding user response:

I'm not 100 % sure what's going wrong in your specific example.

But you only have to pass the address of the struct or the address of the element, not both. In this case:

struct user ***logged_user

Then you can modify the element with:

strcpy((**logged_user)->password, input);

Now if you would only care about the password and not the username in this function, you could have passed in a pointer to only the password, and not the container struct. But that's your choice.

Now there are some other concerns with this code. You need to make sure the copy from input doesn't cause a buffer overrun in (**logged_user)->password. You can either do this by making sure the input is small enough, or using the strncpy function instead. Make sure destination becomes null terminated, typically with (**logger_user)->password[pass_len - 1] = '\0'

This line fseek(*user_registry, 0, SEEK_CUR - 1);

Is weird, SEEK_CUR - 1 will evaluate to SEEK_SET, which I doubt you want to do.

CodePudding user response:

Well, It works now. Just changed the edit of the struct to the function change_password(). And edited the exact member i wanted to edit.


bool change_password(char *new_password, struct user ***logged_user) {
  char repeat_password[MAXLEN];

  system(CLEAR);

  printf("\nInput the new password: ");
  trim_line(get_input(new_password, MAXLEN));

  printf("\nRepeat the new password: ");
  trim_line(get_input(repeat_password, MAXLEN));

  if (0 != strcmp(new_password, repeat_password)) {
    fprintf(stderr, "\nNew password mismatch!\n");
    printf(KEY_PRESS);
    free_buffer();
    return false;
  }

  strcpy((**logged_user)->data.password, new_password);
  return true;
}

After that I pass the struct to the change_user_data() function and done

void change_user_data(bool is_valid, struct user ***logged_user,
                      FILE **user_registry) {
  // making sure the returned input is valid.
  if (!is_valid)
    return;

  struct user find_user;

  fseek(*user_registry, 0, SEEK_SET);
  while (!feof(*user_registry)) {
    fread(&find_user, sizeof(struct user), 1, *user_registry);

    if (0 != strcmp(find_user.data.user_name, (**logged_user)->data.user_name))
      continue;

    fseek(*user_registry, 0, SEEK_CUR - 1);
    fwrite((**logged_user), sizeof(struct user), 1, *user_registry);

    break;
  }
  return;
}

I still need to implement the other advice I was given, like not using feof(), and placing myself correctly in the file, but it's a start.

  • Related