Passing struct to functions - c

Hey I'm not sure why when I pass a Struct array to a function; When I try to access it's members it prints random number. Below the statement "printf("%d\n", netTopo[0].nodes[1]);" works correct but I'm in the function and try print the same data, it prints a bunch of random number? Not sure what I'm doing wrong.
int main(int argc, char *argv[]) {
if (argc != 3){
printf("Incorrect command line arguments. Required 2 files.\n");
exit(-1);
}
FILE *netFile, *schFile; // put into a loop
netFile = fopen(argv[1], "r");
schFile = fopen(argv[2], "r");
int *sched = getSchedFile(schFile);
struct nodeInfo *netTopo = getTopology(netFile);
printf("%d\n", netTopo[0].nodes[1]);
int nodeSocks[nodeCount];
for (int i=0; i<nodeCount; i++){
nodeSocks[i]=getSocketNo();
}
get_elapsed_time(); // start clock
for (int i=0; i<nodeCount; i++){
if (fork()==0){
nodeExecution(i, nodeSocks, netTopo, sched);
exit(0);
}
}
}
void nodeExecution(int id, int nodes[], struct nodeInfo *netTopo, int *schd){
printf("%d\n", netTopo[0].nodes[1]);
......

so you return a pointer to local var on stack from getTopology()? that's the bug.
netTopo is on stack and when you return from getTopology() there are other function calls which would reuse the memory region where netTopo is stored. That memory is modified and you get different output when calling nodeExecution()
ADD: to fix this you may allocate memory in getTopology():
struct nodeInfo* getTopology(FILE *file){
int id, digit=0, totLinks=0;
fscanf(file, "%d", &nodeCount);
struct nodeInfo * netTopo = malloc(sizeof(struct nodeInfo)*nodeCount);
....

Related

Passing array of struct to function in C

Do I need a * in front of my struct array (in the function arguments) when passing the struct to a function by reference? The reason I am thinking we don't is because an array is essential going to pass the address in which the first object is located.
I feel like I just got lucky my code is working:
#include <stdio.h>
struct member {
char lastName[30];
char gender;
int age;
};
void readAndUpdate(struct member *people[]);
// begin main function
int main(void){
struct member *people[30];
readAndUpdate(people);
} // end main function
// begin function which reads a .dat file and propogates the array with the data in the .dat file
void readAndUpdate(struct member *people[]){
}
I worked on my code some more from the help of the commentors and I have the following which works properly. I accidentally created an array of pointers.
#include <stdio.h>
#define MAXPEOPLE 3
struct member {
char lastName[30];
char gender;
int age;
};
void readAndUpdate(struct member *person, size_t maxpeople);
void populateDatFile();
void displayMembers(struct member *person, size_t maxpeople);
// begin main function
int main(void){
struct member people[2];
populateDatFile(); // program will first populate the .dat file with the given specs
readAndUpdate(people, MAXPEOPLE);
printf("The data was read and input as follows:\n\n");
displayMembers(people, MAXPEOPLE);
} // end main function
// function which displays the entire array of struct members
void displayMembers(struct member *person, size_t maxpeople){
int i=0;
for (i=0;i<3;i++){
printf("%s ", person[i].lastName);
printf("%c ", person[i].gender);
printf("%d ", person[i].age);
printf("\n");
}
} // end displayMembers function
// function which loads the .dat file with hardcoded structs
void populateDatFile(){
struct member person1={"Gates", 'M', 60};
struct member person2={"Jobs", 'M', 55};
struct member person3={"Jane", 'F', 45};
FILE *file;
file = fopen("question3.dat","w");
if(file == NULL)
printf("question3.dat cannot be opened!\n");
else
printf("question3.dat was opened successfully.\n");
fprintf(file, "%s %c %d\n", person1.lastName, person1.gender, person1.age);
fprintf(file, "%s %c %d\n", person2.lastName, person2.gender, person2.age);
fprintf(file, "%s %c %d\n", person3.lastName, person3.gender, person3.age);
fclose(file);
} // end function populateDatFile
// begin function which reads a .dat file and propogates the array with the data in the .dat file
void readAndUpdate(struct member *person, size_t maxpeople){
int i=0;
FILE *file;
file = fopen("question3.dat","r");
if(file == NULL)
printf("question3.dat cannot be opened!\n");
else
printf("question3.dat was opened successfully.\n");
fscanf(file, "%s", &person->lastName);
fscanf(file, " %c", &person->gender);
fscanf(file, "%d", &person->age);
fscanf(file, "%s", &person[1].lastName);
fscanf(file, " %c", &person[1].gender);
fscanf(file, "%d", &person[1].age);
fscanf(file, "%s", &person[2].lastName);
fscanf(file, " %c", &person[2].gender);
fscanf(file, "%d", &person[2].age);
fclose(file);
} // end function readAndUpdate
The code you have is 'OK, but…'. And there are some quite significant "buts" to be worried about.
The first issue is whether what you wrote is what you intended to write. You've defined an array of pointers to structures, but not initialized it at all. You may have intended to define an array of structures rather than an array of pointers, which then alters the rest of the discussion. For the time being, I'm taking what you wrote as "it's OK — that's what I intended to write".
You pass the array to the function correctly. The function has no idea how big an array you passed, though. You should get into the habit of telling functions how big the array is.
You don't reference the array inside the function. That's not all bad; you haven't defined the memory that each of the pointers in the array is pointing to. You'll presumably dynamically allocate the items as you add them, and then reference them correctly using arrows -> and not dots .:
void readAndUpdate(size_t max, struct member *people[max])
{
for (size_t i = 0; i < max; i++)
{
people[i] = malloc(sizeof(*people[i]));
if (people[i] == NULL)
…handle error appropriately…
strcpy(people[i]->lastName, "Unknown");
people[i]->gender = 'N'; // Neuter — unknown
people[i]->age = 0; // Babies only
}
}
int main(void)
{
struct member *people[30] = { NULL };
readAndUpdate(30, people);
return 0;
}
If the number of entries isn't actually fixed, then the readAndUpdate() function should report how many were initialized.
I didn't intend to create an array of pointers.
OK; then the rules of the game change:
void readAndUpdate(size_t max, struct member people[max])
{
for (size_t i = 0; i < max; i++)
{
strcpy(people[i].lastName, "Unknown");
people[i].gender = 'N'; // Neuter — unknown
people[i].age = 0; // Babies only
}
}
int main(void)
{
struct member people[30] = { { "", 0, 0 } };
readAndUpdate(30, people);
return 0;
}
The structures are already allocated, and initialized to all bytes zero. The code in the function uses . instead of -> to reference members. The * goes from the variable and parameter definitions.

Segmentation fault 11, issue using pointers and returning them

i keep getting a segmentation fault when running this program. I'm attempting to read the files (inserted into the command line), and allocate the x and y coordinates in each file to a dynamically allocated memory struct called POINTS (using the function called readPoints). After they have been saved into these structs, i then pass them to the function calls calc where the x and y values are multiplied, and then added onto the next x and y multiplied.. so on. Could someone please explain to me where i went wrong! I am not great at pointers.
Thank you in advance.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
float xcord;
float ycord;
}POINTS;
int readPoints(char* file, int numofpoints);
int calc(POINTS* points, int numofpoints);
int main(int argc, char* argv[])
{
int numoffiles;
FILE* file;
int result, i;
numoffiles = argc;
POINTS* pointer;
int numofpoints;
if(numoffiles == 1)
{
printf("Please enter a file\n");
}
for(i=1; i<numoffiles; i++)
{
file = fopen(argv[i], "r");
fscanf(file, "%d", &numofpoints);
pointer = readPoints(file, numofpoints);
if( pointer == NULL)
{
printf("Error return from readPoints function");
}
result = calc(&pointer[i], numoffiles);
printf("%12f", result);
free(pointer);
}
}
int readPoints(char* file,int numofpoints)
{
int i, j;
POINTS* Pointstructs;
Pointstructs = (POINTS*)malloc((numofpoints)*sizeof(POINTS));
if(file == NULL)
{
printf("Error transferring file into readPoints\n");
}
for(i=0; i<numofpoints; i++)
{
fscanf(*file, "%f, %f", &Pointstructs[i].xcord, &Pointstructs[i].ycord);
printf("%f, %f", Pointstructs[i].xcord, Pointstructs[i].ycord);
}
return Pointstructs;
}
int calc(POINTS* points, int numofpoints)
{
int i=0, j=0;
int answer;
while(i<numofpoints && j<numofpoints)
{
answer += points[i].xcord * points[j].ycord;
i++;
j++;
}
return answer;
}
readpoints functions should take its first argument as file pointer BCS fopen returns FILE pointer but u are using char pointer. fscanf first argument should be a file pointer. Pls correct it

Getting core dumps when free() is used

I'm doing a school assignment and the driver was given to me along with the header file. My job is to complete the functions that read data from a text file and then search it for a name and return the email address. It's a huge exercise in using pointers and structures.
The program reads in a text file of names and email addresses then dynamically creates a structure array using malloc(). The struct Card is built of two char pointers and I find the length of the data using strlen(), malloc() memory for that size and assign the struct to the memory address given.
It all seems to work fine until the end after it has printed the name and email and is about to free() the memory. I get an Aborted (core dump) message every time. Don't know what the issue could be.
I've placed a printf() just before the free() to try and track down where the issue is but it appears to be happening either during the name/email printout or just after it happens because my printf() test point that is one line before the free() is never executed.
I'm assuming the driver program is okay and it has something to do with my functions.
Anyone care to take a stab at it?
//Main
#include <stdio.h>
#include <stdlib.h>
#include "lab9utils.h"
int main(int argc, char * argv[]) {
// Variable declarations.
struct Card * cards;
int size;
int k;
char * email;
// Make sure we have 2 extra command-line paramgers.
if (argc < 3) {
printf("Usage: ./lab9.exe <data_filename> <name_to_lookup>");
return 0;
}
// Get the cards and do the lookup.
cards = getCards(argv[1], &size);
email = lookup(cards, argv[2], size);
// Display the output message ("sorry!" or "name -> email").
if (email == NULL) {
printf("Sorry, that name was not in the list of cards.\n");
} else {
printf("%s -> %s\n", argv[2], email);
}
// Free the memory used by the structures.
k = 0;
printf("Test Point#1");
for (k = 0; k < size; k++) {
free(cards[k].name);
free(cards[k].email);
}
printf("Test Point#2");
free(cards);
return 0;
}
// Header
#ifndef LAB9UTILS_H
#define LAB9UTILS_H
struct Card {
char * name;
char * email;
};
struct Card * getCards(char * filename, int * size);
char * lookup(struct Card * cards, char * name, int size);
#endif
// Functions
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lab9utils.h"
struct Card * getCards(char * filename, int * size_return) {
int i,size;
char cTempName[51]={0};
char cTempEmail[51]={0};
size = 0;
// I/O Setup
FILE *fp;
fp = fopen(filename,"r");
// error checking
if(fp == NULL)
{
perror("Error in opening file");
return(NULL);
}
// Input Loop
while(!feof(fp))
{
fscanf(fp,"%s%s",cTempName,cTempEmail);
size++;
}
size=size-1;
fclose(fp);
struct Card * card = (struct Card *)malloc(*size_return * sizeof(struct Card));
fp = fopen( filename ,"r");
// error checking
if(fp == NULL)
{
perror("Error in opening file");
return(NULL);
}
for(i=0;i<size;i++)
{
fscanf(fp,"%s%s",cTempName,cTempEmail);
card[i].name=(char *)malloc((strlen(cTempName)+1));
card[i].email=(char *)malloc((strlen(cTempEmail)+1));
strcpy(card[i].name,cTempName);
strcpy(card[i].email,cTempEmail);
}
fclose(fp);
// loop to confirm data was read
for(i=0;i<size;i++)
{
printf("[ %d ] Name:%s email:%s Total size:%d\n",i,card[i].name,card[i].email,size);
}
*size_return = size;
return card;
}
char * lookup(struct Card * cards, char * name, int size) {
int i;
for(i=0;i<size;i++)
{
if (strcmp(cards[i].name,name)==0)
{
return cards[i].email;
}
}
return NULL;
}
The value of *size_return is garbage, because you are setting it to size only at the end of the function.
Change this:
struct Card * card = (struct Card *)malloc(*size_return * sizeof(struct Card));
To this:
struct Card * card = (struct Card *)malloc(size * sizeof(struct Card));

Struct arrays in C

Hi I'm having trouble trying to initializing each element of the struct array. When I try and assign the value ZERO to both 'bSize' and 'msgs', it doesn't work as it errors out when i get to malloc. In the printf statement it prints a -1852803823 number. Excuse the messy code as i'm playing around trying to figure it out.
struct message{
int *data;
int bSize;
int msgs;
};
int main(int argc, char *argv[]) {
.....
}
void getSchedFile (FILE *file, int **schd) {
struct message sMsg[nodeCount];
const int pakSize = 6;
// Iniitialise message buffer
for (int i=0; i<nodeCount; i++){
sMsg[i].bSize = 0;
sMsg[i].msgs = 0;
printf("bSize %d\n",sMsg[i].bSize);
}
/* Get the number of bytes */
fseek(file, 0L, SEEK_SET);
int time;
while((fscanf(file, "%d", &time)) != EOF){
int src;
fscanf(file, "%d", &src); // get source node id
// These are here for easier reading code
int aPos = sMsg[src].bSize;
int nMsg = sMsg[src].msgs;
printf("size %d\n", sMsg[src].bSize);
if (sMsg[src].bSize==0){
sMsg[src].data = malloc( pakSize * sizeof(int));
}else{
sMsg[src].data = realloc(sMsg[src].data, (aPos+pakSize)*sizeof(int));
}
Where is the nodeCount value coming from? Is it a global variable? You should be very careful with global variables, and avoid using them if possible.
Pass the nodeCount in the method parameter and as Charlie mentioned, check it for > 0

How to pass struct array into a function and correctly store value in it?

I would like to read a file that has the sample number, values and status(1.1, 23,0). I used a Struct to hold that information. I will pass the function struct array and the file location.
#include <stdio.h>
struct Data_point
{
long sampleNumber;
double value;
int status;
};
int filldata(struct Data_point *a, const char *filelocation)
{
FILE *f;
if((f=fopen(filelocation,"r"))==NULL)
{
printf("You cannot open");
}
fscanf(f, "%ld%lf%d", a.sampleNumber, a.value, a.status);
}
int main(void)
{
struct Data_point data[10];
filldata(data, "/home/alexchan/IntrotoC/rec11/dataPoints.txt");
return 0;
}
But, I got an error saying, "request for member not a structure"...
One problem is that the filldata() is taking a pointer argument. So you use -> to address members not ".". So a.sampleNumber should be a->sampleNumber for example.
Another issue is that filldata() is reading in a single struct, but you are passing it the pointer to the top of the array, which is synonymous with &(data[0]). So this function will just overwrite that first element if you call it repeatedly (which you didn't). If you call it in a loop you will need to pass it in pointers to the individual array members:
for(int i = 0; i < 10; ++i){
filldata(&(data[i]), "/home/alexchan/IntrotoC/rec11/dataPoints.txt");
}
You could actually use data + i as the first arg instead of &(data[i]) but I like the latter as I find it more readable.
struct Data_point *a is your function arugument and you are passing data which is a array. So basically you are trying to acess members from a array which is not a struct.
May be
for( int i=0; i<10;++i)
filldata(data[i],.....)
and
int filldata( struct Data_point a,...) //as you are using a.
fscanf requires a pointer-to-data for each passed argument. Use the AddressOf operator & to get a reference to each struct member:
int filldata(const char *filelocation, struct Data_point *a, int nElements)
{
int n = 0;
FILE *f = fopen(filelocation, "r");
if(f)
{
while (fscanf(f, "(%ld,%lf,%d)", &(a[n].sampleNumber), &(a[n].value), &(a[n].status)) == 3 && n < nElements)
n++;
fclose(f);
}
else { printf("Unable to open '%s'\n", filelocation); }
return n;
}
Now, this function is slightly different to yours. You need to tell it how long the array you're passing in as the "a" parameter is. It will return the number of successfully filled entries.
i.e
int main(int argc, char **argv)
{
struct Data_point data[10];
int n = filldata("C:\\Users\\254288b\\temp.txt", data, sizeof(data) / sizeof(struct Data_point));
printf("%d Data_point's were filled successfully.\n\n", n);
for(int i = 0; i < n; i++)
{
printf("Sample Number: %ld\n", data[i].sampleNumber);
printf("Value: %lf\n", data[i].value);
printf("Status: %d\n", data[i].status);
printf("----------------------------\n");
}
return 0;
}
Do note, my pattern for fscanf expects your file to be like:
(100,1.1,10)(200,2.2,20)(300,3.3,30)(400,4.4,40)
Each set is enclosed in parenthesis.

Resources