-4

Preface: I've been learning C this past summer and only recently started learning C++ so I don't know very much of it yet.

I've been trying to write a C/C++ program that recognizes right and left mouse clicks in windows and saves which button was clicked and when into an array of pointers to strings char **clicks. I'm organizing it as a sequence like: button, time, button, time...

Whenever a mouseclick is detected, it takes either "R" or "L" and does this:

void writeClick(char *button) {
    static char **tracker = clicks;
    *tracker = button;
    tracker++;
    time_t seconds = time(NULL);
    *tracker = ctime(&seconds);
    tracker++;
}

My question: The issue you may have noticed is that each array element with the time will be pointing to the same string. The result is that the time will update on each mouse click, but it will only remember the last saved time. I figured I could solve the problem with strcpy, but if I want to save multiple strings then won't I need a new variable for each string? Or a new memory location each time or something? How should I do this?

I tried using strcpy like so:

strcpy(*tracker, ctime(&seconds));

But at the second click my program crashes and I'm not sure why.

Other information that may be useful:

I'm planning on sending the data into VBA because I want to turn it into an Excel spreadsheet.

I've yet to write the part of my code that dynamically increases the array whenever it gets full, but at the moment it's large enough (50 elements) to contain the data for a few clicks without crashing, so I know that's probably not the issue.

The part of my code that detects mouseclicks uses a Windows function and aside from that I don't think my code is affected by which OS I'm using. I don't have any issues with click detection (because I solved them all already).

A friend told me she would just use C++ strings and vectors to do the job, but I don't know them yet. I'll look them up but I'm hoping to find a solution without that if possible.

  • If you are indeed learning C++, don't bother finding a solution _without that if possible_. Just use the right tools available, the standard library, and forget about (char) pointers. – Tas Aug 09 '17 at 00:31
  • @Tas Except `ctime` is part of the standard library, is the right tool available, and uses char pointers. Nothing wrong with copying its return value into a std::string, but understanding why that's necessary will involve learning about char pointers (and static variables, which are the actual point of confusion here). – Ray Aug 09 '17 at 01:34
  • Sorry, my point was only just "don't worry about _not_ using `std::string`", because it's the right tool for the job. Ultimately, OP doesn't need to understand static variables or char* or anything else, because if they'd just had used `std::string` they wouldn't be having issues with those things. IMO, simply having `std::string time = ctime(&seconds);` doesn't need to be understood – Tas Aug 09 '17 at 01:50
  • Thanks guys. I wanted to try doing this /before/ getting deeper into C++ because I wanted a break from it and was looking to see how I can write the code with tools I'm mostly familiar with already. Trying to solve the problem highlighted an aspect of pointers I hadn't fully grasped, and now I know a method of dealing with it in C. Once I get deeper into C++ I'll definitely be rewriting the code. – Josh Glazer Aug 09 '17 at 02:07

1 Answers1

2

From cppreference.com's page on ctime

Return value

Pointer to a static null-terminated character string holding the textual representation of date and time. The string may be shared between std::asctime and std::ctime, and may be overwritten on each invocation of any of those functions.

So yes, the next call to ctime or asctime can be expected to overwrite the buffer used by the previous call.

strcpy(*tracker, ctime(&seconds));

Most likely fails because no storage has been allocated for *tracker to hold the string in.

You could

*tracker = strdup(ctime(&seconds));

to allocate and copy, but this leaves you with the problem of keeping track of which elements of tracker you have to manually free. This will get incredibly nasty fast. If you wish to do this with C, you will either have to strdup and free everything, add in a book-keeping structure to tell you whether or not you dynamically allocated storage and thus must free, or do an extensive redesign.

Since you have tagged C++, follow your friend's advice and use std::vector and std::string.

Documentation on strdup.

Documentation on std::vector.

Documentation on std::string.

Community
  • 1
  • 1
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • Thanks for your reply! But wouldn't I want to keep the string I copied throughout the program's runtime? You said it would cause a memory leak, but I want to keep that data until the program decides to stop, send the info to Excel, and close. Unless you you're envisioning a program that sends data to Excel packet-by-packet rather than all at once...? – Josh Glazer Aug 09 '17 at 01:34
  • @JoshGlazer If your goal is to keep the data until program termination, then you can `strdup` until you run out of storage and let the runtime handle cleanup at exit. But document the crap out of what you've done so that those who follow know what you've done and why and won't be surprised when they use the code under different circumstances. If this is a school assignment the marker could raise questions about why you've deviated from best practices, so it's still in your best interests to explain the choice well. – user4581301 Aug 09 '17 at 01:50