Is there any difference between returning a pointer to a struct, and returning a struct? Aside from the derefrenceing that is done would they both be working with the same struct? Is there any copying that gets done if it is just a regular return?
overwraith 83 Newbie Poster
jeffcogswell 175 Light Poster Featured Poster
When you have a function in C (or C++), the function gets an area of memory on the stack to use for its local variables. If you create a variable like this:
MyStruct X;
inside your function, then the X structure will get created on the stack. If you return the variable like this:
return X;
then when the function ends, the code can't return the actual structure that's on the stack, since that stack space goes away (out of scope). So the code will actually create a copy of it and return that copy by copying over the members. However, the way around that is to allocate the structure on the heap, and instead pass around pointers to that structure. Then you're always working with the same copy. (In C++ you can accomplish this same thing using the new keyword.)
Does that help?
Jeff
overwraith 83 Newbie Poster
Ok, I think I see, so when the code leaves the method it actually has to copy the struct from where it has been allocated to the method that called it right? So if you return a pointer it might be a little more efficient than copying the whole thing, but wouldn't it still have to copy the struct because the area on the stack is gone?
jeffcogswell 175 Light Poster Featured Poster
Correct, except for the part about the pointer. When you allocate something on the heap, the heap stays around and is there for all the functions to share. (In C, I think you use "malloc" to allocate it on the heap. I haven't done straight C in years though.) So what you do is this: In your function, you allocate the structure on the heap, and get back a pointer to that structure. At the end of your function, you return the pointer. The code that called the function gets the pointer to that same spot on the heap, and continues working on the structure. So that's actually a good bit more efficient. Also, if you're doing C++, by calling new, your object automatically gets allocated on the heap and you get back a pointer to it.
overwraith 83 Newbie Poster
I am actually looking back at one of my old C programs that I wrote in a C/C++ data structures class. Apparently it was very efficient according to the teacher, but am looking back to determine why it was efficient.
So if you do not allocate on the heap and you do pass a pointer back to main, then the program will have to move the struct elsewhere?
jeffcogswell 175 Light Poster Featured Poster
No, when it's on the heap it stays right there and the main and other functions just access it through the pointer. The pointer gets passed around and anyone can use it.
overwraith 83 Newbie Poster
Wait now, how did it get on the heap?
jeffcogswell 175 Light Poster Featured Poster
Oh! Sorry, I guess I didn't explain that. When you call malloc in C or new in C++, it gets created on the heap and you get a pointer to its location in the heap.
jeffcogswell 175 Light Poster Featured Poster
So you don't actually have to copy it into the heap. It gets created there.
overwraith 83 Newbie Poster
But what if you don't use malloc? Does the variable then get copied to the heap?
What if you deliberately place the struct on the stack?
It has been a while since I have coded C, so I hope this makes sense?
Edited by overwraith
Moschops 683 Practically a Master Poster Featured Poster
I think you're asking what happens in this case:
someObject* giveMeAnObject()
{
someObject anInstance;
return &anInstance;
}
So you get back a pointer to an object made inside the function, on the stack.
What happens is the memory is now available for other use and you're left with a pointer to a piece of memory that could contain anything, and might even segFault if the OS has decided you're not allowed to look at that memory anymore. This is as bad as it sounds.
Edited by Moschops
overwraith 83 Newbie Poster
C doesn't have objects silly! But basically yes, if you choose to allocate your struct without the malloc method, on the stack (I'm not saying that's what I did in my code), and then return the address of that stack allocated struct, would you still be able to access it, would it move it's slef to the heap, or what.
From what you are saying, it would be popped off the stack and unavailable to the coder.
From what I learned here, allocating to the heap is a really good idea, and can be very benificial to efficiency.
Thanks everybody for bearing with me.
Moschops 683 Practically a Master Poster Featured Poster
C doesn't have objects silly!
Yeah, sure it doesn't. I'm just imagining int, double, char, and all the structs I can think of :)
cambalinho 142 Practically a Posting Shark
but you can create instances\objects of structurs, enums, types(int, double...) and others
overwraith 83 Newbie Poster
Yeah, sure it doesn't. I'm just imagining int, double, char, and all the structs I can think of :)
The cirriculum at my school says so, it might be mistaken, or I could have even interpreted it wrong. Dunno.
Moschops 683 Practically a Master Poster Featured Poster
We're old school. If it takes up memory and has some kind of label, it's an object. Functions, variables, the lot. :)
jeffcogswell 175 Light Poster Featured Poster
This is actually a really good discussion, something I suspect a lot of beginning and even intermediate programmers might be wondering about. I think I'll write my next Tutorial about this topic. (I work for Daniweb as a volunteer.)
overwraith 83 Newbie Poster
I wrote this bit of code while I was in the class. If I ever did it over, there are a few things that I would change, but there is a lot of potential in the code. Basically this "batch" master record/transaction record processor uses this passing of pointers to heap allocated structs to preform it's work. Combines two files, the transaction file, and the old master file into the new master file. It really reads the file almost like the file it's slef is the list. One of the things that should probably be fixed is that it does not write to a binary file, it writes to a text file (that just happens to have a .dat extension, I know I was younger when I wrote it, I didn't know). The loop in main may also need some work.
/*
Author: Cameron Block
Assignment: 11.7, 11.8
File: FileMatching.c
Purpose: Develop a program that does various operations on a file.
*/
#include <stdio.h>//standard input/output
#include <assert.h>
#include <stdlib.h>//malloc cmd for allocating structs
#include <string.h>//memset cmd for clearing memory
char *removeNewLine(char input[]);
typedef struct{//struct for old master file
int accountNum;
float currentBalance;
char name[32];
}MasterRecord;
typedef struct{//struct for transfer file
int accountNum;
float dollarAmmt;
}TransRecord;
MasterRecord *readMasterFileRecord();//pointers are really awesome
TransRecord *readTransactionRecord();
void writeNewMasterRecord(MasterRecord *record);
MasterRecord *createMasterRecord(TransRecord *input, char *name);//creates a new initialized master file record
char *strStrip(char input[]);
void main()
{
//both transactions file, and master file must be in order
MasterRecord *currentMaster=readMasterFileRecord();
TransRecord *currentTransaction=readTransactionRecord();
while(currentMaster!=NULL)
{
while(currentTransaction!=NULL)
{
if((currentTransaction->accountNum)==(currentMaster->accountNum))
{
currentMaster->currentBalance+=currentTransaction->dollarAmmt;
//not entirely sure if it should be +=, or -=
}
else if(currentTransaction->accountNum > currentMaster->accountNum)
{
writeNewMasterRecord(currentMaster);
currentMaster=readMasterFileRecord();
if(currentMaster== NULL){
currentMaster=createMasterRecord(currentTransaction,
"Uninitialized Record");
printf("Unmatched Transaction Record for account number %d\n", currentMaster->accountNum);
//have to put currenbBal += dollarAmt here for this to work
//for some reason, just discovered it through tryal and error
currentMaster->currentBalance+=currentTransaction->dollarAmmt;
continue;
}
if(currentMaster->accountNum == currentTransaction->accountNum)
continue;
else if(currentTransaction->accountNum < currentMaster->accountNum){
currentMaster=createMasterRecord(currentTransaction,
"Uninitialized Record");
printf("Unmatched Transaction Record for account number %d\n", currentMaster->accountNum);
continue;
}
}
else
break;
currentTransaction=readTransactionRecord();
}
writeNewMasterRecord(currentMaster);
currentMaster=readMasterFileRecord();
}
writeNewMasterRecord(NULL);//to close the file
printf("The New Master File has been updated. . . \n");
system("pause");
}
char *removeNewLine(char input[])
{//removes and replaces newline character with a space
int i;
for(i=0;i<strlen(input);i++)
if(input[i]=='\n')
input[i]=' ';
return input;//for a chaining like effect
}
MasterRecord *readMasterFileRecord()
{//originally intended to put the pointers this function returned in an array, or list
//note to self..., in C
//FILE is all caps, and NULL is all caps
static FILE *ofPtr=NULL;
static char nameBuffer[64];
static int firstRun=1;//only set to 1 the first time called
MasterRecord *oldStuff=(MasterRecord*)malloc(sizeof(MasterRecord));
if(oldStuff==NULL)//should return null if fails malloc fails
return oldStuff;
memset(nameBuffer, '\0', 64);
memset(oldStuff, '\0', sizeof(MasterRecord));
//if these files dont exist theres no point in running the program
if(firstRun)//if is first time called get a new pointer
assert((ofPtr=fopen("oldmast.dat", "rb"))!=NULL);
firstRun=0;//want this set to 0 after the first time through the function
if(feof(ofPtr))//if is end of file return null
{
fclose(ofPtr);
return NULL;
}
//read one struct from old master file
//fscanf returns the number of arguments it successfully accomplished
//if there is a blank line fscanf will return a number less than its
//number of arguments, which is 2.
if(fscanf(ofPtr, "%d %f", &oldStuff->accountNum, &oldStuff->currentBalance)<2)
return NULL;
//get the rest of the line and do some formatting to it, first and last name
strcpy(&oldStuff->name, strStrip(removeNewLine(fgets(&nameBuffer, 64, ofPtr))));
return oldStuff;
}
TransRecord *readTransactionRecord()
{//this function not done yet
static FILE *tfPtr=NULL;
static int firstRun=1;
TransRecord *transStuff=(TransRecord*)malloc(sizeof(MasterRecord));
if(transStuff==NULL)//malloc has failed
return transStuff;//return NULL
memset(transStuff, '\0', sizeof(TransRecord));
if(firstRun)
assert((tfPtr=fopen("trans.dat", "rb"))!=NULL);
firstRun=0;
if(feof(tfPtr))
{
fclose(tfPtr);
return NULL;
}
if(fscanf(tfPtr, " %d %f", &transStuff->accountNum, &transStuff->dollarAmmt)<2)
return NULL;
return transStuff;
}
void writeNewMasterRecord(MasterRecord *record)
{
static int firstRun = 1;
static FILE *nfPtr=NULL;
if(firstRun)
assert((nfPtr=fopen("newmast.dat", "wb"))!=NULL);
firstRun=0;
if(record==NULL)
{
fclose(nfPtr);
return;
}
fprintf(nfPtr, "%d %.2f %s\n", record->accountNum, record->currentBalance, record->name);
fflush(nfPtr);
}
MasterRecord *createMasterRecord(TransRecord *input, char *name)//creates a new initialized master file record
{
MasterRecord *newStuff=(MasterRecord*)malloc(sizeof(MasterRecord));
memset(newStuff, '\0', sizeof(MasterRecord));
//a little extra protection if someone decides to foreget to write a null character
newStuff->accountNum=input->accountNum;
//we do not set the current balance because this way the loop sets it for us.
//if we did end up putting it in here it would assign it twice
strcpy(&newStuff->name, name);
return newStuff;
}
char *strStrip(char input[])
{//removes trailing and preceding whitespace
int i, j, first, last;
char *trimmedstr;
for(i=0;i<strlen(input);i++)//read from left to right
if(input[i]!=' '){//find first instance of a not space
first=i;//log it
break;}
for(i=strlen(input);i>0;i--)//read from right to left
if(input[i]!=' '&&input[i]!='\0'){//find first instance of a not space
last=i;//log it
break;}
//allocate string, subtract unwanted characters
trimmedstr=calloc(strlen(input)-first-(strlen(input)-last)+1, sizeof(char));
trimmedstr[strlen(input)-first-(strlen(input)-last)+1]='\0';
for(i=first, j=0;i<=last;i++, j++)
trimmedstr[j]=input[i];
return trimmedstr;
}
//oldmast.dat
100 348.17 Alan Jones
300 27.19 Mary Smith
500 0.00 Sam Sharp
700 -14.22 Suzy Green
//trans.dat
100 27.14
300 62.11
400 100.56
400 123.50
400 123.50
900 82.17
900 82.17
900 82.17
//newmast.dat
100 375.31 Alan Jones
300 89.30 Mary Smith
400 347.56 Uninitialized Record
700 -14.22 Suzy Green
900 246.51 Uninitialized Record
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.