Hey guys,
I have been doing some serious practice with structs and I have set myself a little project. The idea is a basic user registration process. I have been working on this for about two weeks but I've become really stuck the last couple of days.
The flow of the code is this:
I've created a set of data structs for various different types of info. Then a user template struct which is a struct of pointers to all the other structs. I want a way to dynamically create and allocate this information as new users are created, on demand. So I've created a function that returns a pointer to a mallocated space. After asking for a last name (as a small test exercise), it inputs the name to a pseudo-random number generator and generates a system and user id. This all works just fine. The problem I have is passing the pointers by reference to the function that inputs the appropriate data to the new struct.
Here is the code:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
*
*/
struct systemid_struct {
uint systemID;
uint userID;
};
struct personalname_struct {
char firstName[24];
char lastName[24];
};
struct username_struct {
char userName[24]; //enter a comparison function so that usernames are not the same as first or last name
};
struct email_struct {
char email[32];
};
struct password_struct {
char password[25]; //enter the same comparison function for passwords, look up how to securely store passwords in C
};
struct dob_struct {
short age;
short day;
short month;
uint year;
};
struct physical_struct {
float weight;
float height;
};
struct user_template_struct {
struct systemid_struct *sytemtemp;
struct personalname_struct *personaltemp;
struct username_struct *usernametemp;
struct email_struct *emailtemp;
struct password_struct *passwdtemp;
struct dob_struct *detailstemp;
struct physical_struct *physicaltemp;
};
// write a fn that creates a user template struct of pointers for each user
struct user_template_struct *createuserfn (){
struct user_template_struct *userptr = malloc(sizeof(*userptr));
return userptr;
}
int fillbasicinfo(struct user_template_struct *userptr, uint* systemID, uint* userID, char* lastName){
for(uint i=0; i<1; i++){
userptr->sytemtemp->systemID = *systemID;
userptr->sytemtemp->userID = *userID;
printf("fillbasicinfo USERID: %u\n fillbasicinfo SYSTEMID: %u\n", userptr->sytemtemp->userID, userptr->sytemtemp->systemID);
}
for(uint i=0; i<24; i++){
userptr->personaltemp->lastName[i] = lastName[i];
printf("fillbasicinfo lastNAME: %c\n", lastName[i]);
}
return 0;
}
// then write a fn that stores all the users within another struct of pointers
int main(int argc, char** argv) {
uint systemID;
uint userID;
char lastName[24];
uint* systemIDptr;
uint* userIDptr;
char* lastNameptr;
struct user_template_struct *userlistptr;
systemIDptr = &systemID;
userIDptr = &userID;
lastNameptr = &lastName[0];
printf("%s", "Welcome, please Enter your last name \n");
scanf("%s", lastName);
printf("Your last name is: %s \n", lastName);
printf("%s", "Thank you, please wait a moment \n");
srand(strlen(lastName));
uint randomid = rand();
userID = randomid;
printf("Your user ID is: %u \n", userID);
srand(userID);
systemID = rand();
printf("Your system ID is: %u \n", systemID);
userlistptr = createuserfn();
printf("\n The struct for the new user is at address: %p\n", userlistptr);
int userfillerror = fillbasicinfo(&userlistptr, &systemIDptr, &userIDptr, &lastNameptr);
printf("%d", userfillerror);
return (EXIT_SUCCESS);
}
and here is the initial ouput:
Code:
cd '/home/access/NetBeansProjects/username_practice'
/usr/bin/make -f Makefile CONF=Debug
"/usr/bin/make" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
make[1]: Entering directory '/home/access/NetBeansProjects/username_practice'
"/usr/bin/make" -f nbproject/Makefile-Debug.mk dist/Debug/GNU-Linux/username_practice
make[2]: Entering directory '/home/access/NetBeansProjects/username_practice'
mkdir -p build/Debug/GNU-Linux
rm -f "build/Debug/GNU-Linux/main.o.d"
gcc -c -g -MMD -MP -MF "build/Debug/GNU-Linux/main.o.d" -o build/Debug/GNU-Linux/main.o main.c
main.c: In function ‘main’:
main.c:161:39: warning: passing argument 1 of ‘fillbasicinfo’ from incompatible pointer type [-Wincompatible-pointer-types]
int userfillerror = fillbasicinfo(&userlistptr, &systemIDptr, &userIDptr, &lastNameptr);
^
main.c:105:5: note: expected ‘struct user_template_struct *’ but argument is of type ‘struct user_template_struct **’
int fillbasicinfo(struct user_template_struct *userptr, uint* systemID, uint* userID, char* lastName){
^~~~~~~~~~~~~
main.c:161:53: warning: passing argument 2 of ‘fillbasicinfo’ from incompatible pointer type [-Wincompatible-pointer-types]
int userfillerror = fillbasicinfo(&userlistptr, &systemIDptr, &userIDptr, &lastNameptr);
^
main.c:105:5: note: expected ‘uint * {aka unsigned int *}’ but argument is of type ‘uint ** {aka unsigned int **}’
int fillbasicinfo(struct user_template_struct *userptr, uint* systemID, uint* userID, char* lastName){
^~~~~~~~~~~~~
main.c:161:67: warning: passing argument 3 of ‘fillbasicinfo’ from incompatible pointer type [-Wincompatible-pointer-types]
int userfillerror = fillbasicinfo(&userlistptr, &systemIDptr, &userIDptr, &lastNameptr);
^
main.c:105:5: note: expected ‘uint * {aka unsigned int *}’ but argument is of type ‘uint ** {aka unsigned int **}’
int fillbasicinfo(struct user_template_struct *userptr, uint* systemID, uint* userID, char* lastName){
^~~~~~~~~~~~~
main.c:161:79: warning: passing argument 4 of ‘fillbasicinfo’ from incompatible pointer type [-Wincompatible-pointer-types]
int userfillerror = fillbasicinfo(&userlistptr, &systemIDptr, &userIDptr, &lastNameptr);
^
main.c:105:5: note: expected ‘char *’ but argument is of type ‘char **’
int fillbasicinfo(struct user_template_struct *userptr, uint* systemID, uint* userID, char* lastName){
^~~~~~~~~~~~~
mkdir -p dist/Debug/GNU-Linux
gcc -o dist/Debug/GNU-Linux/username_practice build/Debug/GNU-Linux/main.o
make[2]: Leaving directory '/home/access/NetBeansProjects/username_practice'
make[1]: Leaving directory '/home/access/NetBeansProjects/username_practice'
BUILD SUCCESSFUL (total time: 234ms)
As you can see it compiles fine, eventually with no errors. But of course, the code doesn't execute properly. I have tried to declare the parameters as double pointers but then my build completely fails.
Here is the result from running the code:
Code:
Welcome, please Enter your last name
asdfasdfasdf
Your last name is: asdfasdfasdf
Thank you, please wait a moment
Your user ID is: 1687063760
Your system ID is: 374848126
The struct for the new user is at address: 0xd88830
fillbasicinfo USERID: 2024348112
fillbasicinfo SYSTEMID: 2024348116
fillbasicinfo lastNAME: �
fillbasicinfo lastNAME:
fillbasicinfo lastNAME: �
fillbasicinfo lastNAME: x
fillbasicinfo lastNAME: �
fillbasicinfo lastNAME:
fillbasicinfo lastNAME:
fillbasicinfo lastNAME:
fillbasicinfo lastNAME: �
fillbasicinfo lastNAME:
fillbasicinfo lastNAME: �
fillbasicinfo lastNAME: x
fillbasicinfo lastNAME: �
fillbasicinfo lastNAME:
fillbasicinfo lastNAME:
fillbasicinfo lastNAME:
fillbasicinfo lastNAME: �
fillbasicinfo lastNAME:
fillbasicinfo lastNAME: �
fillbasicinfo lastNAME: x
fillbasicinfo lastNAME: �
fillbasicinfo lastNAME:
fillbasicinfo lastNAME:
fillbasicinfo lastNAME:
0
RUN FINISHED; exit value 0; real time: 4s; user: 0ms; system: 0ms
I understand how to write to an array and read from it via a pointer, it's not rocket science. All the operators seem fine and autofill gives me the correct array when I use the deference operator. I have practiced reading to and writing from arrays via structs and pointers using the deference operator, I can't see what would be different here.
Why am I getting these garbage values? And why is the System/UserID's different when output from inside the function than from the initial generation?
I have tried declaring the parameters as double pointers and also tried to pass them directly i.e. without the ampersand. Both of these ideas resulted in build fail.
It should be noted that this all worked just fine when fillbasicinfo and createuserfn were one function. But I felt that to be rather un-kosher for C. Hence this approach.
Thanks in advance
MedicineMan25