I've had these functions working fine, before I change one of the Strings via sscanf.
I.e., If I have a char[] NAME that I create in the (called) function, and initialize it to a string (eg "fred";), then assign that to the passed parameter -> The parameter changes in its parent function.
But if I try to change the string (NAME) with input from fgets -> sscanf, then assign it to the passed array, the parent function prints nothing ('blank').
I'm trying to figure out the char-array vs. pointer situation. And I thought I had it; I could change the passed String with a local (initialized) string. But once I assign some 'user input' to the local string, the parameter-string isn't being altered properly.
Here are my functions...
int enter_record(FILE *fp, const char *prompt[]) {
char *name[BUFFER] = {"wram"};
int score = 12; /* REPLACE : Put 0 or something ! */
fprintf(fp, "Enter_record()\n%s\n", *prompt); /* This is only here to use variables; so wil compile */
printf("Score: %d\n", score);
printf("Name:%s\n", *name);
get_name(prompt, name);
printf("Post-Change Name:%s\n", *name);
return 1;
}
int get_name(const char *prompt[], char *fullName[]) {
int n; /* The number of strings scanned */
char line[BUFFER]; /* The line that is scanned */
char firstString[BUFFER]; /* First scanned string */
char midString[BUFFER]; /* Second scanned string (',' ?) */
char lastString[BUFFER]; /* Last string scanned */
/* Function call validation */
printf("get_name()\n%s\n", *prompt);
if( !fgets(line, BUFFER, stdin) ) {
clearerr(stdin);
return 0; /* If *EOF* return FALSE */
}
if( !(n = sscanf(line, " %[a-zA-Z-] %[a-zA-Z-,] %[a-zA-Z-] %*s", firstString, midString, lastString)) ) {
printf("Wrong format!!!!\n");
}
printf("n:%d\n", n);
printf("firstString:%s\n", firstString);
*fullName= firstString;
return 1;
}
Below I'll include the remainder of my code (main, menu, etc..)
#include <stdio.h>
#define BUFFER 512
#define NAMELENGTH 14
int menu(const char *choices[], const char *prompt[]);
int enter_record(FILE *fp, const char *prompt[]);
int get_name(const char *prompt[], char *fullName[]);
int main(int argc, char *argv[]) {
FILE *ofp;
const char *menuOptions[] = {"Enter record", "Display records", "Quit", '\0'};
const char *prompt[2] = {"> "}; /* Prompt for user to enter input */
int menuResult;
/* Command line ARGS validation */
/*
VALIDATES main() is called correctly from console.
*/
/* Ensure program envoked correctly */
if(argc != 2) {
fprintf(stderr, "usage: %s [destination file]\n", argv[0]);
return 1; /* Incorrect-envocation error */
}
/* Open file for student records */
if( (ofp = fopen(argv[1], "wb+")) == 0) { /*If there's an error */
perror("fopen");
return 2; /* File-open error */
}
/*
///// END VALIDATION for main() call.
*/
printf("main()\n");
while(1) {
menuResult = menu(menuOptions, prompt);
switch(menuResult) {
case 0: /* Menu returned FALSE; */
return 0;
case 1: /* Enter Record; choice */
enter_record(ofp, prompt);
break;
default:
break;
}
}
return 0;
}
int menu(const char *choices[], const char *prompt[]) {
int i; /* Used to print menu "choice" "Number" */
char input[BUFFER]; /* The line scanned by fgets */
int choice = 0; /* What the user chooses */
int choiceLen = -1; /* Used to track how many elements in "choices[]"
This is used because (in my code) 'QUIT' is always last option
*/
/* Calculates # elements in *choices[] */
while (choices[++choiceLen] != NULL) {};
printf("\n");
for (i=0; choices[i] != '\0'; i++){
printf("%1d. %s\n", i+1, choices[i]);
}
while(1) {
printf("%s", *prompt);
if(!fgets(input, BUFFER, stdin)) {
clearerr(stdin);
return 0;
}
sscanf(input, "%d %*s", &choice);
if(choice == choiceLen) /* QUIT is always last option (choiceLen) */
return 0; /* Return QUIT */
else if ((choice > 0) && (choice < choiceLen)) /* 0 is invalid choice */
return choice;
}
return 0;
}
If some one could point out to me where I have gone wrong; Why would changing the variable with sscanf change the way the parent's-variable is affected? My confusion lies in the fact that it worked when the 'child-string' is pre-initialized (E.g. char name[BUFFER] = {"Bob"}; ), but not after I'd altered it with sscanf.
If my problem lies elsewhere, please let me know as well.
A pointer in any direction would be appreciated.
Cheers.
The problem is here:
char line[BUFFER];
char firstString[BUFFER];
char midString[BUFFER];
char lastString[BUFFER];
These are local variables, which means the character arrays are in the stack frame; this memory is freed when function get_name
finishes. It is wrong to expose a pointer to this memory to the outside world (i.e. function enter_record
).
The easiest solution is to allocate the string buffers in static memory:
static char line[BUFFER];
static char firstString[BUFFER];
static char midString[BUFFER];
static char lastString[BUFFER];
This approach does have a few disadvantages.
Alternatives are:
enter_record
instead of get_name
, which extends their lifetime accordingly. Let enter_record
pass pointers to the buffers upon calling get_name
.malloc
. I must say I'm not in favor of having get_name
allocate memory, then let enter_record
free it; it kind of hurts maintainability.