C passing string between functions - c

I'm writing simple program in C and got stucked. I have three functions:
void changeStatusOfBook(User users[], Book books[]) {
char *id= askForBookID();
Book book = getBookById(books, id);
.
.
.
}
char * askForBookID() {
char id[6];
printf("Tell me which book (ID)\n");
scanf_s("%5s",id, 6);
return id;
}
Book getBookById(Book books[], char bookID[]) {
int counter = 0;
//bookID becomes a trash here
.
.
.
}
The problem is: In the first function I get correct user string input, but when I pass it to third function I'm getting some trash in it. How to fix it?

You can't return a local variable char id[] from a function.It's memory is on the stack and when the function returns all stack memory for that function and its local variables are no more accessible.
when memory is need on the stack for another program it overrides the memory space for char id, and this becomes a problem for your program.
char * askForBookID() {
//char id[6];
char *id = malloc(sizeof(char)*6);
if(!id){ //check if malloc got some memory for id
printf("Sorry not enough memory"); return NULL;
}
printf("Tell me which book (ID)\n");
scanf_s("%5s",id, 6);
return id;
}

The function askForBookID returns the address of the first element of an array with automatic storage duration.
The behaviour on your using that pointer oncce the function has been called is undefined.
Use malloc instead.

Related

C - Unable to copy a string in a function

This function is to split string based on \n and see if the row number is selected. If the row number matched, this string should be copied and used by other function:
void selectDeparment(char* departments, int selectedNum, char* selectedDepartment){
char* copyOfDepartments = malloc(strlen(departments)+1);
strcpy(copyOfDepartments,departments);
char* sav1 = NULL;
char* token = strtok_s(copyOfDepartments,"\n",&sav1);
int counter = 0;
while(token != NULL){
if(counter == selectedNum){
selectedDepartment = malloc(strlen(token)+1);
strcpy(selectedDepartment,token);
}
++counter;
token = strtok_s(NULL, "\n", &sav1);
}
}
This function is called in main like:
char* selectedDepartment;
selectDeparment(recordsPtr[0], 1, selectedDepartment);
printf(selectedDepartment);
recordsPtr[0] contains four strings with \n at the end:
aDeparment
anotherDepartment
newDepartment
otherDepartment
In C, we are encouraged to use pointer to get a value from function instead of returning a string from a function. However, the prinft in main function gives random output
I believe there is some confusion in the way you are using pointers here. Let me clarify.
In the main function, the character pointer selectedDepartment holds a certain memory in the computer. But when a function call is made to void selectDeparment(char* departments, int selectedNum, char* selectedDepartment), a new copy of selectedDepartment is created. Henceforth any changes which are made to selectedDepartment are done only at the scope of the called function and does not impact the original pointer in the main function.
Thus one clear way to solve this problem will be to pass a pointer to the character pointer defined in the main function. This will then give the correct/expected results.
Here is the modified version of the function -
void selectDeparment(char* departments, int selectedNum, char** selectedDepartment){
char* copyOfDepartments = malloc(strlen(departments)+1);
strcpy(copyOfDepartments,departments);
char* sav1 = NULL;
char* token = strtok_s(copyOfDepartments,"\n",&sav1);
int counter = 0;
while(token != NULL){
if(counter == selectedNum){
(*selectedDepartment) = malloc(strlen(token)+1);
strcpy(*selectedDepartment,token);
}
++counter;
token = strtok_s(NULL, "\n", &sav1);
}
}
And this is how it is called from the main function -
int main() {
char* recordsPtr[] = {"aDeparment\nanotherDepartment\nnewDepartment\notherDepartment"};
char* selectedDepartment;
selectDeparment(recordsPtr[0], 1, &selectedDepartment);
printf(selectedDepartment);
}
I think you are getting confused with the "A Pointer To What?" you are supposed to return. In your selectDeparment() function, if I understand what is needed, is you simply need to return a pointer to the correct department within recordsPTR. You do not need to allocate or tokenize to do that. You already have the index for the department. So simply change the return-type to char * and return departments[selectedNum];.
For example, you can whittle-down your example to:
#include <stdio.h>
char *selectDeparment (char **departments, int selectedNum){
return departments[selectedNum];
}
int main (void) {
char *selectedDepartment = NULL;
char *recordsPTR[] = { "aDepartment\n",
"anotherDepartment\n",
"newDepartment\n",
"otherDepartment\n" };
selectedDepartment = selectDeparment (recordsPTR, 1);
fputs (selectedDepartment, stdout);
}
Note: the '*' generally goes with the variable name and not the type. Why? Because:
int* a, b, c;
certainly does NOT declare three-pointers to int,
int *a, b, c;
makes clear that you have declared a single-pointer to int and two integers.
Example Use/Output
Running the example above you would have:
$ ./bin/selectedDept
anotherDepartment
You will want to add array bounds protection to ensure the index passed does not attempt to read past the array bounds. That is left to you.
If You Must Use void
If you must use a void type function, then you can pass the Address Of the pointer to the function so the function receives the original address for the pointer in main(). You can then assign the correct department to the original pointer address so the change is visible back in main(). When you pass the Address Of the pointer, it will require one additional level of indirection, e.g.
#include <stdio.h>
void selectDeparment (char **departments, int selectedNum, char **selectedDeparment) {
*selectedDeparment = departments[selectedNum];
}
int main (void) {
char *selectedDepartment = NULL;
char *recordsPTR[] = { "aDepartment\n",
"anotherDepartment\n",
"newDepartment\n",
"otherDepartment\n" };
selectDeparment (recordsPTR, 1, &selectedDepartment);
fputs (selectedDepartment, stdout);
}
(same result, same comment on adding array bounds protection)
Look this over and let me know if I filled in the missing pieces correctly. If not, just drop a comment and I'm happy to help further.

return makes integer from pointer without a cast when returning a struct

Im writing a code for a school project where we are defining a library and I cant get my function to return correctly
I have tried to redefine my code and change int init_book to int *init_book but that only gives me other errors
int init_book(struct book *p_book, const char *p_id, const char *p_title, const char * p_author, struct date p_release) {
p_book = malloc(sizeof(struct book));
for (int i = 0; i < 10; i++) {
p_book->id[i] = p_id[i];
}
p_book->title = malloc(strlen(p_title) * sizeof(char));
p_book->author = malloc(strlen(p_author) * sizeof(char));
p_book->title = p_title;
p_book->author = p_author;
p_book->release_date = p_release;
return p_book;
}
//a part of my main function that initiates the function
if (init_book(&a1, "000000009", "Harry Potter and the Philosopher's Stone", "J. K. Rowling", a1date)) {
printf("Initialization succeeded\n");
printf("%s\n", a1.title);
//it prints initialization succeeded but not a1.title
}
else {
printf("Initialization failed\n");
}
You are attempting to return a struct book * but you declared the function as returning int (or int *). This can’t work.
You need to change the return type to struct book *. Next, remove the unnecessary p_book parameter and convert it into a local variable: It has no use. The result looks like this:
struct book *init_book(const char *p_id, const char *p_title, const char * p_author, struct date p_release) {
struct book *p_book = malloc(sizeof *p_book);
for (int i = 0; i < 10; i++) {
p_book->id[i] = p_id[i];
}
p_book->title = malloc(strlen(p_title) + 1);
p_book->author = malloc(strlen(p_author) + 1);
strcpy(p_book->title, p_title);
strcpy(p_book->author, p_author);
p_book->release_date = p_release;
return p_book;
}
(I’ve also fixed the errors in the string allocation and copying in your code: your code didn’t allocate sufficient space, but the allocation was leaked anyway since you moved pointers instead of copying the contents.)
And it’s called like this:
struct book *p_book = init_book("000000009", "Harry Potter and the Philosopher's Stone", "J. K. Rowling", a1date);
if (p_book) {
printf("Initialization succeeded\n");
printf("%s\n", a1.title);
} else {
printf("Initialization failed\n");
}
I'm going to take a different approach to the other answers. I think the return value of your function is intended to be a status rather than the initialized struct book since you are passing in a pointer to the struct book you wish to initialize. In that case, you should not be mallocing the book because the pointer you are passing in should already be to a valid memory location of a struct book.
Use the return value to indicate whether an error has occurred in initialization.
Without knowing more about your struct book it's hard to tell if you need to malloc any of the member variables, or just assign pointers. If you do need to use malloc, then you can use the return code from your calls to malloc to set your own return value to indicate whether or not there was an error.
The return type of a function should match the type of whatever you're trying to return. So to return p_book, of type struct book *, then your return type should be struct book *.

failed while trying to reach pointer in struct

my project is to build book structure - and fill it with users parameters.
involving dynamic allocation, arrays and pointers.
my book structure has the following:
struct BOOK
{
char* author;
char** genders;
int totalGenders;
char* name;
int* chapterPages;
int totalChapters;
}typedef book;
when I tried reaching author name, line 1 in structure:
struct BOOK
{
char* author;
I failed doing that.. my code in main :
int main()
{
book* b;
char authorChar[10] = { 0 };
int authorLen;
char* authorName;
// get author name
puts("please enter the name of the author");
scanf("%s", &authorChar);
authorLen = strlen(authorChar);
printf("%d", authorLen); //print to see that lentgh is correct.
authorName = (char*)calloc(authorLen, sizeof(char));
strcpy(authorName, authorChar);
puts("\n");
b->author = authorName;
printf("%d", b->author);
when i have debugged i got a problem in this line :
b->author = authorName;
ideas please? :)
The problem is in the following line
b->author = authorName;
at this point, b is not allocated memory, i.e., b is an uninitialized pointer. It points to some random memory location which is not a valid one. Any attempt to access invalid memory invokes undefined behavior.
You can use either of the following approach to resolve the issue:
allocate memory to b dynamically before using it, like b = malloc(sizeof*b); and a check for success.
define b as a variable of type book, instead of a pointer-to-type.
That said, int main() should be int main(void) at least, to conform to the standards.
You are forgetting to do the memory allocation for b variable.
b = malloc(sizeof(book));
b->author = malloc(sizeof(100000)); // replace value for the size you want

Keeping the value of a String initialized into a function

I know my title isn't clear, It will be clearer with code + examples.
I want to initialize a char* ("motSecret" in the main, "mot" in my function) containing a word selected randomly into a file, doing this into a function. This array is made dynamic using memory allocation.
The variable in my function get well initialized, but when I print the value just after I exited the function, the value change and become something like "0#"
Here is the part concerned in the main :
int main()
{
FILE* dico =NULL;
char *motSecret, *motRes;
char lettre=' ';
int check=0, nbCoups=10, longueur=0, nbMots=0;
Bool erreur = TRUE;
srand(time(NULL));
nbMots = scanDico(dico);
getWord(dico, nbMots, motSecret);
printf("Mot : %s", motSecret);
The problem appears after the function getWord(). Here is the code of this function :
void getWord(FILE* dico, int nbLignes, char *mot)
{
int numMotChoisi=rand() % nbLignes, nbChar=0;
char charActuel=' ';
dico = fopen("dico.txt", "r");
rewind(dico);
if(dico != NULL)
{
while (numMotChoisi > 0)
{
charActuel = fgetc(dico);
if (charActuel == '\n')
numMotChoisi--;
}
charActuel = ' ';
while(charActuel != '\n')
{
charActuel = fgetc(dico);
nbChar++;
}
fseek(dico,-(nbChar)-1,SEEK_CUR);
mot = malloc(nbChar * sizeof(char));
if(mot == NULL)
{
printf("Probleme d'allocation memoire");
exit(0);
}
fgets(mot, SIZE, dico);
mot[strlen(mot) - 1] = '\0';
printf("Mot = %s ", mot);
}
fclose(dico);
}
The printf at the end of the function return a good value, and the printf just after the getWord() in the main show that the value changed in the function haven't been "saved"...
Other thing, that works fine without memory allocation.
I hope I'm clear enough. If I forgot to tell something or if you need more informations, please tell me.
C uses pass by value in function parameter passing.
You need a double pointer, something like void getWord(FILE* dico, int nbLignes, char **mot) if you want to allocate memory inside another function.
As a cascased effect, printf("Mot : %s", motSecret); is trying to access uninitialized memory, causing undefined behaviour.
Suggestions:
I see no reason to use FILE *dico as a parameter in getWord(). In can very well be a local.
instead of using double pointer, i would like to recommend returning the allocated pointer from getWord(), i.e., change void getWord() to char * getWord(), add return mot and use like motSecret = getWord(<params>)
char *motSecret;
motSecret is a local variable withing main() and it is not initilized.
By calling
getWord(dico, nbMots, motSecret);
You are passing some uninitialized pointer to a function getword().
Inside getword() you are assigning some memory to
char *mot;
and writing some data to this memory.
Now this memory is not known to motSecret You have to return this memory address to the uninitialized pointer in main()
char *motSecret = getWord(dico, nbMots);
Your getword() should be like,
char *getWord(dico, nbMots);
and inside this after performing everything do,
return mot;

Populating linked list function not storing data in structure and crashing on print

So I'm working on a little C program which is a little address book that automatically allocates memory when you add a new contact in it.
I'm using two typedef structures, the first one stores the info on the contact (name telephone etc.):
typedef struct
{
char nom[TAILLE1];
char tel[TAILLE2];
} CONTACT;
The seconde one contains a int with the number of contacts in the address book and an other one is the pointer to the other structure.
typedef struct
{
int nb;
CONTACT * contacts; // tableau
} LISTE_TABLEAU;
I created a function to import contact from a TXT file (first line the name of the person, second line their telephone number and so on). I simplified it with only the basic
int lireDonneesTxt(LISTE_TABLEAU* tab)
{
int i;
tab->contacts = (CONTACT *)malloc(sizeof(CONTACT)*13); (13 because there are 13 contact for testing purposes)
i = 0;
while( !feof(entree) )
{
fgets(ligne, TAILLE1, entree);
strcpy(tab->contacts[i].nom, ligne);
fgets(ligne, TAILLE1, entree);
strcpy(tab->contacts[i].tel, ligne);
i++
}
return 1;
}
When I compile my code there isn't any issue, no warning what so ever.
But when I run my code everything works great until I try and print a name on the screen, then the executable file crashes.
My main function looks something like this:
int main(void)
{
LISTE_TABLEAU *tabb;
tabb->nb = 0;
lireDonneesTxt(&tabb);
printf("%s", tabb->contacts[0].nom);
return 0;
}
If I add the same printf that is in the main at the end of my lireDonneesTxt function it prints the name without any problem.
I'm guessing that the data is not passed correctly to the structure.
I am now blocked and have no idea what to try to make this work !
Don't pass the address of the LISTE_TABLEAU pointer here:
lireDonneesTxt(&tabb);
just pass the pointer
lireDonneesTxt(tabb);
Also setting tabb->nb = 0; to unalocated memory is undefined behaviour.
The memory is not allocated for "tabb" & you are trying to access its member variable (tabb->nb) in main() function. It is illegal, thus the run time crash.
You can try the below code instead:
int main(void)
{
LISTE_TABLEAU tabb;
tabb.nb = 0;
lireDonneesTxt(&tabb);
printf("%s", tabb.contacts[0].nom);
return 0;
}

Resources