CloudWave
CloudWave

Reputation: 1085

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 enter image description here

Upvotes: 0

Views: 69

Answers (2)

Rishabh Agarwal
Rishabh Agarwal

Reputation: 149

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);
}

Upvotes: 1

David C. Rankin
David C. Rankin

Reputation: 84551

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.

Upvotes: 0

Related Questions