0

Trying to learn C. To that end, I'm coding a program that creates a TroubleTicket report. The user is prompted to enter, priority, name and problem. I'm using a struct to store the data and create a struck array. Using the array approach for now as I'm developing the code. Eventually, I'd to use a linked list.

Anyhow, the get_input() function reads in the user input and returns a char pointer. Included the get_input() and create_ticket() functions.

#define NUM_TICKETS 10

char* get_input(int maxlen)
{
    static char s[110];
    char ch;
    int i = 0;
    int chars_remain = 1;

    while (chars_remain)
    {
        ch = getchar();
        if ((ch == '\n') || (ch == EOF))
        {
            chars_remain = 0;
        }
        else if (i < maxlen - 1)
        {
            s[i] = ch;
            i++;
        }
    }
    s[i] = '\0';
    return s;
    
void create_ticket()
{
    struct ticket
    {
        int priority;
        int number;
        char * name;
        char * problem ;
        char * assigned_to;
        char * status ;
    };
    struct ticket tkt_array[NUM_TICKETS];
    struct ticket new_ticket;
    
    printf("Enter your name: ");
    new_ticket.name = get_input(20);
    printf("new_ticket.name: %s \n", new_ticket.name);
        
    printf("Enter problem description: ");
    new_ticket.problem = get_input(100);
    printf("new_ticket.problem: %s \n", new_ticket.problem);
    
    printf("Assigned to: ");
    new_ticket.assigned_to = get_input(20);
    printf("new_ticket.assigned_to %s\n ", new_ticket.assigned_to);
    
    printf("Enter ticket status: ");
    new_ticket.status = get_input(10);
    printf("new_ticket.status: %s \n", new_ticket.status);
    
}

I noticed that initial input was read and displayed correctly but subsequent inputs overwrote prior input.

For example, after name was entered, the entered value is displayed

printf("Enter your name: ");
new_ticket.name = get_input(20);
printf("new_ticket.name: %s \n", new_ticket.name);

But after problem description is entered, new_ticket.name was changed to display the problem description text. Took me a while to figure out that the problem is the return s in get_char(). It returns a pointer. The address is the same but the value changes and struct ticket pointers point to the same address of return s from get_char(). How can I save the return value in a variable and not get it reset on subsequent call to get_input? s is a char *, how can I save the return value of a pointer in a variable?

printf("Enter problem description: ");
new_ticket.problem = get_input(100);
printf("new_ticket.problem: %s \n", new_ticket.problem);
printf("new_ticket.name: %s \n", new_ticket.name);

How can I save the return value in a variable and not get it reset on subsequent call to get_input? s is a char *, how can I save the return value of a pointer in a variable? I hope I clearly stated the issue.

8
  • 1
    Please note that getchar returns and int value. This is rather important when you want to compare it with the int value EOF. Commented Nov 22, 2022 at 17:35
  • Where do you want to save the string? Commented Nov 22, 2022 at 17:36
  • As for your problem, the static array in get_input, I recommend that you create an array in the calling function and pass it in to the get input instead: char *get_input(char *buffer, size_t buflen); Commented Nov 22, 2022 at 17:37
  • 1
    By the way, you do understand the meaning and semantics of local static variables in functions? Commented Nov 22, 2022 at 17:40
  • Andrew, Missing } before void create_ticket(). Please review posted code for compilation correctness. Commented Nov 22, 2022 at 17:42

2 Answers 2

2

This answer addresses only the problem stated in the question, not other errors or problems in your code.

Your function get_input uses a single array static char s[110]; to store the input and always returns the address of this array.

Assignments like new_ticket.name = get_input(20); will store the same address in all pointer variables, so all will actually point to the same variable s which will contain the last input.

One option to solve this would be to replace the pointers in your structure with arrays and either pass this to get_input or copy the value using strcpy.

Or you could use the (non-standard) function strdup to get a dynamically allocated duplicate of the input string. If this function is not available, you could implement it using malloc and strcpy.

Example:

    new_ticket.name = strdup(get_input(20));

Note: When using strdup, you should free the memory when it's no longer needed.

or using a replacement for strdup:

    const char *s1;
    char *s2;
/* ... */

    s1 = get_input(20);
    s2 = malloc(strlen(s1) + 1);
    if(s2 == NULL)
    {
        /* handle error */
    }
    else
    {
        strcpy(s2, s1);
    }
    new_ticket.name = s2;

(You could implement your own function that wraps malloc and strcpy.)

or with arrays instead of pointers as structure fields

    struct ticket
    {
        int priority;
        int number;
        char name[20];
        char problem[100];
        char assigned_to[20];
        char status[10];
    };

/* ... */
    strcpy(new_ticket.name, get_input(sizeof(new_ticket.name));
Sign up to request clarification or add additional context in comments.

4 Comments

I tried using arrays as the sample shows but stack size error message. That's why I used pointers
Ended up using strdup(). VS2019 complained and instructed to use _strdup so I just added #define strdup _strdup and code is working.
@Andrew This is because strdup is in POSIX but not in the C standard. Note that you should free the memory allocated by strdup when it's no longer needed.
Thanks for that info. I didn't know I had to use free. I assumed that strdup() called free.
1

The static keyword creates a value that exists once, so multiple invocations of the function point to the same data.

If you want to dynamically create data with a lifetime that you control, you may allocate your own memory.

malloc(size) will allocate a block of memory with the size provided. This memory will exist and be valid until you call free on that memory.

You should be careful though, calling free twice, or forgetting to call it at all, are common sources of bugs within c code.

The other option in this is to have the caller of the function provide the memory. You could change your struct ticket to have char name[MAX_NAME_LEN], and update the function get input to get_input(int max_len, char * buffer). This also solves the problem, while avoiding potentially erroneous malloc and frees.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.