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));
Related
I have currently made this much of the code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#define STRSIZE 21
struct PInven{
int count;
struct PItem{
char name[STRSIZE];
int amount;
}Pitem;
}Pinven;//this needs to be an output file
int ReadInProduce (){
//read in file and check to see if the file exist or not.
FILE * PinFile = fopen("produce.txt","r");
if (PinFile == NULL){
printf("ERROR: WRONG FILE");
}
else{
printf("I did it!!\n");
}
//assigning the value gotten into the struct variable(but need to maybe change this since it needs to be an output)
fscanf(PinFile,"%d",&Pinven.count);
printf("%d\n", Pinven.count);
int i;
for(i =0; i <Pinven.count; i++){
fscanf(PinFile,"%20s %d",Pinven.Pitem.name, &Pinven.Pitem.amount);
printf("%s %d\n",Pinven.Pitem.name, Pinven.Pitem.amount);
}
//making an array to hold the variables
//FILE * PoutFile = fopen("produce_update.txt","w");
fclose(PinFile);
return 0;
}
From there I want to get the file that is read to the structs to be printed out into an array so that later on I can make a function that will be able to compare to the to it.
Basically a store management system. Where the file of the inventory is read in and compared to the file that is store and return a new value for the amount of produce now either left or gained.
10 //number of items that will be stored in the store
apple 19
banana 31
broccoli 9
...
In general, it's a really bad idea to include header information in the file about the number of entries in the file. You want to be able to do stream processing, and that will be more difficult if you need that meta-data. More importantly, it is important to understand how to write the code so that you don't need it. It's not really that difficult, but for some reason people avoid it. One simple approach is just to grow the array for each entry. This is horribly inefficient, but for the sake of simplicity, here's an example that expects the file not not include that first line:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <limits.h>
#define STRSIZE 128
struct PItem{
char name[STRSIZE];
int amount;
};
struct PInven{
int count;
struct PItem *PItem;
};
static void
grow(struct PInven *p)
{
p->PItem = realloc(p->PItem, ++p->count * sizeof *p->PItem);
if( p->PItem == NULL ){
perror("out of memory");
exit(1);
}
}
int
ReadInProduce(struct PInven *P, const char *path)
{
FILE * PinFile = fopen(path, "r");
if( PinFile == NULL ){
perror(path);
exit(1);
}
char fmt[64];
int max_len;
max_len = snprintf(fmt, 0, "%d", INT_MAX);
snprintf(fmt, sizeof fmt, "%%%ds %%%dd", STRSIZE - 1, max_len - 1);
grow(P);
struct PItem *i = P->PItem;
while( fscanf(PinFile, fmt, i->name, &i->amount) == 2 ){
i += 1;
grow(P);
}
P->count -= 1;
fclose(PinFile); /* Should check for error here! */
return P->count;
}
int
main(int argc, char **argv)
{
struct PInven P = {0};
char *input = argc > 1 ? argv[1] : "produce.txt";
ReadInProduce(&P, input);
struct PItem *t = P.PItem;
for( int i = 0; i < P.count; i++, t++ ){
printf("%10d: %s\n", t->amount, t->name);
}
}
As an exercise for the reader, you should add some error handling. At the moment, this code simply stops reading the input file if there is bad input. Also, it would be a useful exercise to do fewer reallocations.
you should change Structure of PInven to it can save a dynamic array of Pitem with a Pitem pointer.
tested :
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define STRSIZE 21
typedef struct {
char name[STRSIZE];
int amount;
} Pitem;
struct PInven {
int count;
Pitem *pitem;
} Pinven; // this needs to be an output file
int main() {
// read in file and check to see if the file exist or not.
FILE *PinFile = fopen("produce.txt", "r");
if (PinFile == NULL) {
printf("ERROR: WRONG FILE");
} else {
printf("I did it!!\n");
}
// assigning the value gotten into the struct variable(but need to maybe
// change this since it needs to be an output)
fscanf(PinFile, "%d", &Pinven.count);
Pinven.pitem = (Pitem *)malloc(sizeof(Pitem) * Pinven.count);
printf("%d\n", Pinven.count);
int i;
for (i = 0; i < Pinven.count; i++) {
fscanf(PinFile, "%20s %d", Pinven.pitem[i].name,
&Pinven.pitem[i].amount);
// printf("%s %d\n",Pinven.pitem[i].name, Pinven.pitem[i].amount);
}
for (i = 0; i < Pinven.count; i++) {
printf("%s %d\n", Pinven.pitem[i].name, Pinven.pitem[i].amount);
}
// making an array to hold the variables
// FILE * PoutFile = fopen("produce_update.txt","w");
fclose(PinFile);
// remember free
free(Pinven.pitem);
return 0;
}
I am attempting to write a program which will store credential information in an array of structures and then print that information out into a file (this is for learning purposes only, don't worry). To do this, I create an array of structures and then raster through that array to assign the pertinent information to each field. This proceeds without issue. I then attempt to raster through the array again to write each structure's fields to a file whereupon the program crashes after the first write (ie only one structure's worth of content is successfully written to the output file).
I created the following simplified / stripped down variant of my program which reproduces the error. I believe the problem lies within the set_hash_entry function as the error only manifested after that function was re-introduced into my stripped down code in place of a hard coded test value.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "openssl/sha.h"
#include <time.h>
#include <math.h>
struct password_struct {
char password[17];
char hash[65];
float entropy;
};
struct password_struct* allocate_heap_memory(int num_passwords);
void orchestrate_value_setting(int num_passwords, struct password_struct* user_password_structs);
void orchestrate_file_output(int num_passwords, struct password_struct* user_password_structs);
void write_results_to_disk(char file_name[], struct password_struct* user_password_structs);
void set_hash_entry(struct password_struct* user_password_structs);
int main(void) {
int num_passwords = 2;
struct password_struct* user_password_structs = allocate_heap_memory(num_passwords);
struct password_struct* allocated_memory_start_ptr = user_password_structs;
orchestrate_value_setting(num_passwords, user_password_structs);
user_password_structs = allocated_memory_start_ptr; // Resetting pointer to allow cycling back through all structures for appending data to output file
orchestrate_file_output(num_passwords, user_password_structs);
free(allocated_memory_start_ptr);
}
struct password_struct* allocate_heap_memory(int num_passwords) {
struct password_struct* user_password_structs = malloc(num_passwords * sizeof(struct password_struct));
if (!user_password_structs) {
printf("Malloc failed, exiting\n");
exit(0);
}
return user_password_structs;
}
void set_hash_entry(struct password_struct* user_password_structs){
int pass_entry_length = strlen(user_password_structs->password);
SHA256_CTX context;
unsigned char generated_hash[65]; //sha256 standard digest length + 1;
SHA256_Init(&context);
SHA256_Update(&context, (unsigned char *)user_password_structs->password, pass_entry_length);
SHA256_Final(generated_hash, &context);
char* hash_ptr = &user_password_structs->hash[0];
int i;
for (i=0; i < (64); i++) {
snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]); // Need to convert from hex to char representation
}
user_password_structs->hash[64] = '\0';
printf("%s\n", user_password_structs->hash);
}
void orchestrate_value_setting(int num_passwords, struct password_struct* user_password_structs) {
char pw1[10] = "test";
char pw2[10] = "test2";
float entropy1 = 5.0;
float entropy2 = 10.0;
strcpy(user_password_structs->password, pw1);
set_hash_entry(user_password_structs);
user_password_structs->entropy = entropy1;
user_password_structs++;
strcpy(user_password_structs->password, pw2);
set_hash_entry(user_password_structs);
user_password_structs->entropy = entropy2;
user_password_structs++;
}
void orchestrate_file_output(int num_passwords, struct password_struct* user_password_structs) {
printf("Writing data to disk...\n");
char file_name[20] = "name";
int i;
for (i = 0; i < num_passwords; i++) {
write_results_to_disk(file_name, user_password_structs);
user_password_structs++;
}
}
void write_results_to_disk(char file_name[], struct password_struct* user_password_structs) {
FILE *file_pointer = fopen(file_name, "a");
if (file_pointer == NULL) {
printf("Error: Failed to open file\n");
exit(1);
}
fprintf(file_pointer, "%s:%s:%f\n", user_password_structs->password, user_password_structs->hash, user_password_structs->entropy);
fclose(file_pointer);
}
After running this program, the following output is produced:
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752
Writing data to disk...
*** Error in `./diagnostic': free(): invalid next size (normal): 0x0804b0c0 ***
Aborted (core dumped)
I naively assumed this was an overflow issue related to my
snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]);
operation, but increasing the size of the hash buffer in the struct does not seem to help. Any help would be greatly appreciated!
I compiled as follows: gcc -o diagnostic -g diagnostic.c -lcrypto -lm
char hash[65];
Okay, hash has room for 65 characters.
char* hash_ptr = &user_password_structs->hash[0];
So, hash_ptr points to hash, so it points to room for 65 characters.
for (i=0; i < (64); i++) {
snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]); // Need to convert from hex to char representation
}
When i is 60, i*2 is 120. So you're trying to write to the 120th position of a buffer with room for 65 characters.
Change that (64) to 32 in the loop or change hash[65] to a bigger buffer.
Using valgrind found this immediately. You should learn to use some too that detects buffer overflows, use after free, double frees, and similar problems.
There is a function that asks the user which text file to open, opens it and then passes the array of structures that was passed into the function along with the file pointer to another function that reads in data from file into the structure. The array structure for testing purposes only has the value char name[25];. I can assign one line at a time from the file to the same structure index all I want but when I try an increment it I get a segmentation fault no matter what approach I've taken.
The structure has been type defined as well.
The code is:
void oSesame(char usrTxt[], int len, FILE * pFile, Country * p)
{
pFile = fopen(usrTxt, "rw");
if(pFile != NULL)
{
readIn(pFile, &p);
}
else
{
printf("Error opening %s , check your spelling and try again.\n", usrTxt);
}
}
void readIn(FILE * pfile, Country ** p)
{
int count = 0;
int i = 0;
for(i = 0; i<3; i++)
{
fgets((*p[i]).cntName, MAX_COUNTRY_LENGTH, pfile);
}
fclose(pfile);
}
The header file:
//Header.h
#define COUNTRY_MAX 10
#define MAX_COUNTRY_LENGTH 25
#define MAX_CAPITAL_LENGTH 25
typedef struct country
{
char cntName[MAX_COUNTRY_LENGTH];
char capName[MAX_CAPITAL_LENGTH];
double population;
}Country;
int ask(char * usrTxt);
void oSesame(char usrTxt[], int len, FILE * pFile, Country * p);
void readIn(FILE * pFile, Country ** p);
The main code:
#include <stdio.h> //for testing within main
#include <string.h> //for testing within main
#include "headers.h"
int main()
{
int len;
FILE * fileP;
char UI[25];
Country c[10];
Country * ptr;
ptr = c;
len = ask(UI);
oSesame(UI, len, fileP, ptr);
return 0;
}
You are passing Country** for some reason and then handling it as *p[index]. This is wrong. You could use (*p)[index] but the correct way is not to take a reference to the Country* in the first place.
The way you're doing it means you have a pointer to pointer to Country. When you index that you are moving to next pointer to pointer, which is not the same as moving to the next pointer. Undefined behaviour happens.
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);
....
I'm making a program in C, and I'mm having some troubles with memory, I think.
So my problem is: I have 2 functions that return a struct. When I run only one function at a time I have no problem whatsoever. But when I run one after the other I always get an error when writting to the second struct.
Function struct item* ReadFileBIN(char *name) -- reads a binary file.
struct tables* getMesasInfo(char* Filename) -- reads a text file.
My code is this:
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int numberOfTables=0;
int numberOfItems=0;
//struct tables* mesas;
//struct item* Menu;
typedef struct item{
char nome[100];
int id;
float preco;
};
typedef struct tables{
int id;
int capacity;
bool inUse;
};
struct tables* getMesasInfo(char* Filename){
struct tables* mesas;
char *c;
int counter,numberOflines=0,temp=0;
char *filename=Filename;
FILE * G;
G = fopen(filename,"r");
if (G==NULL){
printf("Cannot open file.\n");
}
else{
while (!feof(G)){
fscanf(G, "%s", &c);
numberOflines++;
}
fclose(G);
}
/* Memory allocate for input array */
mesas = (struct tables *)malloc(numberOflines* sizeof(struct tables*));
counter=0;
G=fopen(filename,"r");
while (!feof(G)){
mesas[counter].id=counter;
fscanf(G, "%d", &mesas[counter].capacity);
mesas[counter].inUse= false;
counter++;
}
fclose(G);
numberOfTables = counter;
return mesas;
}
struct item* ReadFileBIN(char *name)
{
int total=0;
int counter;
FILE *ptr_myfile;
struct item my_record;
struct item* Menu;
ptr_myfile=fopen(name,"r");
if (!ptr_myfile)
{
printf("Unable to open file!");
}
while (!feof(ptr_myfile)){
fread(&my_record,sizeof(struct item),1,ptr_myfile);
total=total+1;
}
numberOfItems=total-1;
Menu = (struct item *)calloc(numberOfItems , sizeof(struct item));
fseek(ptr_myfile, sizeof(struct item), SEEK_END);
rewind(ptr_myfile);
for ( counter=1; counter < total ; counter++)
{
fread(&my_record,sizeof(struct item),1,ptr_myfile);
Menu[counter] = my_record;
printf("Nome: %s\n",Menu[counter].nome);
printf("ID: %d\n",Menu[counter].id);
printf("Preco: %f\n",Menu[counter].preco);
}
fclose(ptr_myfile);
return Menu;
}
int _tmain(int argc, _TCHAR* argv[])
{
struct item* tt = ReadFileBIN("menu.dat");
struct tables* t = getMesasInfo("Capacity.txt");
getchar();
}**
the error that im getting is :
"Unhandled exception at 0x00411700 in test.exe: 0xC0000005: Access violation writing location 0x00000000."
in "Menu[counter] = my_record;"
Thanks in advance.
You seem to allocate a memory block of the wrong size in getMesasInfo(): sizeof(struct tables*) gives you the size of the pointer, not that of the struct it is pointing to:
mesas = (struct tables *)malloc(numberOflines* sizeof(struct tables*));
So you can easily overwrite unallocated memory. The proper allocation should be
mesas = (struct tables *)malloc(numberOflines* sizeof(struct tables));
or, similar to how you allocate the other array in ReadFileBIN():
mesas = (struct tables *)calloc(numberOflines, sizeof(struct tables));
Moreover, I don't know whether it's intentional or not, but in ReadFileBIN() you are allocating (1) and reading (2) one less record than the total number of records:
numberOfItems=total-1; // 1
Menu = (struct item *)calloc(numberOfItems , sizeof(struct item)); // 1
fseek(ptr_myfile, sizeof(struct item), SEEK_END);
rewind(ptr_myfile);
for ( counter=1; counter < total ; counter++) // 2
...
Since the loop counter is started from 1 (instead of 0 as is normal in C), you effectively execute the loop total-1 times. That is, you read into elements 1 to total-1 of the array. However, the real elements of the array are indexed from 0 to total-2 so the very first element in the array is left uninitialized, and in the end you commit a buffer overflow error.
You have a problem in these lines:
numberOfItems=total-1;
Menu = (struct item *)calloc(numberOfItems , sizeof(struct item));
fseek(ptr_myfile, sizeof(struct item), SEEK_END);
rewind(ptr_myfile);
for ( counter=1; counter < total ; counter++)
First, you're setting numberOfItems to one less than the total. This is incorrect. You don't even need numberOfItems; since total has the number of lines in the file, the next line should really be Menu = (struct item*) calloc(total, sizeof(struct item));
Second, you're trying to use Menu as a one-based array in the for loop. C arrays are zero-based. You should have the for loop use for (counter = 0; counter < total; counter++).
Finally, as Peter pointed out, in the first function you're allocating the wrong size of object. You need to malloc numberOfLines*(sizeof(struct tables) (not sizeof(struct tables*).
To further illustrate Peter's point:
struct tables {
int id;
int capacity;
int inUse; /* bool is not a C type */
};
int main()
{
printf("sizeof: %d\n",sizeof(struct tables*));
printf("sizeof: %d\n",sizeof(struct tables));
}
Will output:
sizeof: 4
sizeof: 12