GIDForums  

Go Back   GIDForums > Computer Programming Forums > C Programming Language
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 25-Jul-2007, 02:38
pisuke pisuke is offline
New Member
 
Join Date: May 2007
Posts: 19
pisuke is on a distinguished road

Arrays as function arguments - return arrays from functions


Hi there,

That's a follow up of the thread I started yesterday (sfrtime doubt), I thought that the new thread title would be more descriptive, I have already posted a link on the previous thread.

Dave:
I followed your suggestions, and the next step is to place the functionality generating the filenames in a function and either declare the filenames array on the calling function, pass it as a pointer and update it from the called function; or generate the filenames array in the called function and return to the calling function.

To be honest I manage quite well when passing pointers and receiving pointers to simpler data types, but even having read the "C in a nutshell" chapters regarding the subject I lack a bit of understanding when I use arrays, specially multi-dimensional arrays.

I've tried both approaches, but I get different warnings regarding data type conversions. The code follows:

1.- Declaration in the calling function, and filenames array as argument of the called function:
CPP / C++ / C Code:
void get_filenames(char * filenames[])
{
	
	time_t now;
	struct tm *localnow;
	
	time(&now);
	localnow = localtime(&now);
	
	// Data filename
	char data_filename[24];
	strftime(data_filename, 24, "F%Y%m%d-%H%M-data.csv", localnow);
	filenames[0] = data_filename;
	
	// Results filename
	char result_filename[26];
	strftime(result_filename, 26, "F%Y%m%d-%H%M-result.csv", localnow);
	filenames[1] = result_filename;
	
	
} 

int main() {

	char * filenames[2];
	
	get_filenames(filenames);
	
	printf("%s\n", filenames[0]);
	printf("%s\n", filenames[1]);

	return 0;
	
}		// end main


output:
Ð"
F200èapatÌ"

I got no compilation errors.

2.- Filenames array generated in the called function and returned to the called function as a pointer.
CPP / C++ / C Code:

void * get_filenames()
{
	
	time_t now;
	struct tm *localnow;
	char *filenames[2];
	
	time(&now);
	localnow = localtime(&now);
	
	// Data filename
	char data_filename[24];
	strftime(data_filename, 24, "F%Y%m%d-%H%M-data.csv", localnow);
	filenames[0] = data_filename;
	
	// Results filename
	char result_filename[26];
	strftime(result_filename, 26, "F%Y%m%d-%H%M-result.csv", localnow);
	filenames[1] = result_filename;
	
	return filenames;
	
} 

int main() {

	char (* filenames)[2];
	
	filenames = get_filenames();
	
	printf("%s\n", filenames[0]);
	printf("%s\n", filenames[1]);

	return 0;
	
}		// end main



output:
èa. @
a. @


Could anybody clarify a little bit this issue, or just tell where to find some good tutorials on the subject.

Thanks,
Pisuke
  #2  
Old 25-Jul-2007, 08:08
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,620
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: arrays as function arguments - return arrays from functions


Quote:
Originally Posted by pisuke
...new thread title ...link on the previous thread
Perfect!
Quote:
Originally Posted by pisuke

1.- Declaration in the calling function, and filenames array as argument of the called function:
2.- Filenames array generated in the called function and returned to the called function as a pointer.
Either can work. I won't go into the relative advantages of each and when I might prefer one way over the other.

A very important thing about pointers: In order to be useful, a pointer must point to some memory address where you intend to read and write and for which it is legal for you to do so. If you try to access memory by dereferencing a pointer that does not point to a valid block of memory, the result is undefined behavior.

A very important thing about function parameters: All function arguments are "pass by value". You can't pass an array to a function, but you can pass the address of the first element (or any other element as far as that goes). Similarly, you can't return an array from a function. You can pass a pointer to something (an array or anything else).

A very important thing about variables declared inside a function. The variables will go out of scope when the program returns from the function. Memory address of these "local" variables will no longer be valid for access after you leave the function.

A useful thing to remember: If you allocate memory dynamically (with malloc() for example) the pointer that you get will point to a particular block of memory that the operating system has granted you. This will "belong" to the current program until you de-allocate it (with free()), or until your main() function exits (in which case the operating system will reclaim all memory and other resources allocated to that process.

Now for your first example:
Quote:
Originally Posted by pisuke
CPP / C++ / C Code:
void get_filenames(char * filenames[])
{
	
	time_t now;
	struct tm *localnow;
	
	time(&now);
	localnow = localtime(&now);
	
	// Data filename
	char data_filename[24];
	strftime(data_filename, 24, "F%Y%m%d-%H%M-data.csv", localnow);
	filenames[0] = data_filename;
This declares a local array of char. It puts something into the array, and sets the value of the filenames[0] pointer to the address of the first element of the array. That's OK for here, but when you leave this function, the data_filename array is "out of scope", and your program can not legally access it. Since your main program tries to print out whatever it is that filenames[0] points to, it's undefined behavior. Similarly with filenames[1]. Won't work. Period.


Now for the second example:
Quote:
Originally Posted by pisuke
CPP / C++ / C Code:
void * get_filenames()
Why the heck do you declare it a pointer to void? I won't bore you with the details right now, but that's just plain "Not the Thing to Do". However, the fundamental problem is along the lines of what you did in the first example:
CPP / C++ / C Code:
void * get_filenames()
{
	
	time_t now;
	struct tm *localnow;
	char *filenames[2];
.
.
.	
	return filenames;
	
} 

Regardless of the other stuff wrong with this function, this is just plain wrong. You are returning a "local variable" a pointer whose value is the address of a variable that will go out of scope when the return statement is executed. There is no way that the calling function can use this memory legally.


Now, I'll rework your first example to make it functional, although that's not the most useful way to design a function like you have in mind.

CPP / C++ / C Code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void get_filenames(char *filenames[]);

int main()
{

    int i;
    char *filenames[2]; /* an array of two pointers to char */

    get_filenames(filenames);

    for (i = 0; i < 2; i++) {
        if (filenames[i] == NULL) {
            printf("NULL pointer for filenames[%d]\n", i);
        }
        else {
            printf("filenames[%d] = %s\n", i, filenames[i]);
        }
    }
    /*
     * Do whatever you need to do with the filenames
     */
    for (i = 0; i < 2; i++) {
        if (filenames[i] != NULL) {
            free(filenames[i]);
        }
    }


    return 0;

}

/* a function that will create two file names
 * and store pointers to the names in the array
 */
void get_filenames(char *filenames[])
{

    time_t now;
    struct tm *localnow;
    int i;

    time(&now);
    localnow = localtime(&now);

    for (i = 0; i < 2; i++) {
        filenames[i] = malloc(24); /* allocate an array of 24 chars */
        strftime(filenames[i], 24, "F%Y%m%d-%H%M-data.csv", localnow); /* store the string */
    }
}

Output will look something like:
Code:
filenames[0] = F20070725-0701-data.csv filenames[1] = F20070725-0701-data.csv

The most obvious shortcoming (to me, at least) is the function will only work if you want two file names. It should be easy to fix it so that you declare an array of any size you want and give the function a second parameter that tells it how many file names to create:

So your main function would look like:
CPP / C++ / C Code:
void get_filenames(char *filenames[], int number);

int main()
{

    int i;
    char *filenames[10]; /* an array of pointers to char */
    int n = 10;

    get_filenames(filenames, n);

    for (i = 0; i < n; i++) {
        if (filenames[i] == NULL) {
            printf("NULL pointer for filenames[%d]\n", i);
        }
        else {
            printf("filenames[%d] = %s\n", i, filenames[i]);
        }
    }
    /*
     * Do whatever you need to do with the filenames
     */
    for (i = 0; i < n; i++) {
        if (filenames[i] != NULL) {
            free(filenames[i]);
        }
    }
    return 0;

}

The actual changes inside the function are minimal.

There are a few other details that I could throw in, but I'll resist the urge for now, and see if this makes sense to you. (And let you practice with it and see if things are a little more clear.)

Regards,

Dave

Footnote: In case you didn't notice, your functions (mine, too) have another "minor" problem: The file names are not unique. Even if you called time() and localtime() separately for each filename and you used the "seconds" member of the tm struct as part of the name, you have to realize that it takes a lot less than a second to create lots and lots of file names. So you need to come up with some other way to make sure that the names are all different.
  #3  
Old 25-Jul-2007, 11:03
pisuke pisuke is offline
New Member
 
Join Date: May 2007
Posts: 19
pisuke is on a distinguished road

Re: arrays as function arguments - return arrays from functions


Thanks Dave,

So far everything is clear.

Quote:
Originally Posted by davekw7x
Either can work. I won't go into the relative advantages of each and when I might prefer one way over the other.

Perhaps you can post for us which kind of rules do you follow in order to choose one of the approaches.

Quote:
Originally Posted by davekw7x
Why the heck do you declare it a pointer to void? I won't bore you with the details right now...

Well, none of your posts nor posts of some other people in this forum have so far bored me ;-)... I just keep on reading and asking as unfortunately my level is not high enough to solve problems.

Could you post also something about it.

Quote:
Originally Posted by davekw7x
The most obvious shortcoming .... Footnote....

Yes, you are right, why I choose that design:
- This function is thought generate two log files, which are the output from a system measuring conductivity in a moving fluid, this measurement takes about 10 minutes, one file is for the raw data (conductivity lectures): timestamp-data.csv, and the other is for the processed data output timestamp-result.csv.
- Filenames have different length, that's why I don't use a "for" loop in the get_filenames function.
- Due to the measurement time I won't get the problem you mention in your footnote.


Thanks,
Pisuke
 

Recent GIDBlogFirst week of IA training by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
need help with a console menu system BullBuchanan CPP / C++ Forum 6 20-Aug-2006 14:46
[Include] Doubly-linked List dsmith C Programming Language 6 14-Apr-2006 13:12
[Tutorial] Function Pointers aaroncohn CPP / C++ Forum 4 17-Feb-2006 11:33
Problem with one variable bretter CPP / C++ Forum 1 16-May-2005 07:20
C++ file I/O CronoX CPP / C++ Forum 36 09-Mar-2004 17:28

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 14:41.


vBulletin, Copyright © 2000 - 2008, Jelsoft Enterprises Ltd.