I am working on a project and have hit a snag that I have spent hours trying to figure out. I'm fairly certain its very close to correct but obviously something is wrong in my malloc of the struct array. I'll post the code below so you can see it. The goal of this function set is to read in movie data saved in a file and put the data into a structure.
#include <stdio.h>
#include <stdlib.h>
#include "support.h"
#include "scanner.h"
#include <string.h>
int counter(char *movierecords)
{
int count = 0;
char *name;
char *about;
int date;
int time;
char *rate;
char *ppl;
char *dir;
//printf("test");
FILE *fp = fopen(movierecords, "r");
//printf("gggg");
name = readString(fp);
while (!feof(fp))
{
//printf("test in loop");
about = readString(fp);
date = readInt(fp);
time = readInt(fp);
rate = readToken(fp);
ppl = readString(fp);
dir = readString(fp);
//printf("test read");
free(name);
free(about);
free(rate);
free(ppl);
free(dir);
//printf("test free");
count++;
name = readString(fp);
}
//printf("test escape loop");
fclose(fp);
//printf("test file close");
return count;
}
movie **readRecord(char *movierecords, int count) //mallocates space and reads data into an array of movie structures
{
int x = 0;
movie **data1;
FILE *fp = fopen(movierecords, "r");
data1 = malloc(sizeof(struct movie *) * (count + 1)); //mallocate space for the struct array movies1
printf("another test");
while (x < count + 1) //loop mallocates space for the string variables in movies1 struct for all movies
{
data1[x]->moviename = malloc(sizeof(char) * 1001);
data1[x]->description = malloc(sizeof(char) * 2001);
data1[x]->rating = malloc(sizeof(char) * 10);
data1[x]->cast = malloc(sizeof(char) * 512);
data1[x]->director = malloc(sizeof(char) * 30);
x++;
}
printf("test point3\n"); x = 0;
while (!feof(fp))
{
data1[x]->moviename = readString(fp);
data1[x]->description = readString(fp);
data1[x]->year = readInt(fp);
data1[x]->length = readInt(fp);
data1[x]->rating = readToken(fp);
data1[x]->cast = readString(fp);
data1[x]->director = readString(fp);
x++;
}
printf("test point4\n");
fclose(fp);
return data1;
}
Header file:
typedef struct entry
{
char *moviename;
char *description;
int year;
int length;
char *rating;
char *cast;
char *director;
} movie;
int counter(char *movierecords);
movie **readRecord(char *movierecords, int count);
Main:
#include <stdio.h>
#include <stdlib.h>
#include "support.h"
#include <string.h>
int main (int argc, char **argv)
{
int count = 0;
printf("%d", argc);
movie **data1;
count = counter(argv[1]);
printf("%d", count);
printf("hello");
data1 = readRecord(argv[1], count);
return 0;
}
You have to allocate memory for this "data1[x]" because your malloc(double pointer) allocate memory for array of your records(single pointer). Fot the single pointer data[x] you have to allocate memory
Related
I am trying to pass the pointer to a struct to a function to create an array of the struct there. The overall idea is:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct items
{
int number;
char *name;
char *description;
} ITEMS;
int process(ITEMS **items)
{
int i = 0, something = 200;
// for loop is for the representation.
// The actual data come from MySQL row loop
for (int j = 100; j < something; j++)
{
// Growing the array of struct
items = realloc(items, (i + 1) * sizeof(*items));
// Adding items here
items[i]->number = j;
strcpy(items[i]->name, "Some name"); // it comes from a variable
strcpy(items[i]->description, "Some text");
i++;
}
return i;
}
int main()
{
ITEMS *items;
int num_items = process(&items);
for (int i = 0; i < num_items; i++)
{
printf("%d - %s - %s\n", items[i].number, items[i].name,
items[i].description);
}
return 0;
}
but I am struggling with reallocating the memory for the struct (and with the pointers too).
The pointer to pointer must be de-referenced in the function so the allocation is visible in the calling function.
strdup is use to allocate memory to the pointers in the structure.
It is better to use a temporary variable for the reallocation.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct items
{
int number;
char *name;
char *description;
} ITEMS;
int process(ITEMS **items)
{
int i = 0;
// Growing the array of struct
*items = realloc(*items, (i + 1) * sizeof(**items));
// repeating this step in a loop of adding items
// Adding items here
(*items)[i].number = 72;
(*items)[i].name = strdup( "Some name"); // it comes from a variable
(*items)[i].description = strdup ("Some text");
i++;
*items = realloc(*items, (i + 1) * sizeof(**items));
// another item
(*items)[i].number = 88;
(*items)[i].name = strdup( "Some name"); // it comes from a variable
(*items)[i].description = strdup ("Some text");
i++;
return i;
}
int main()
{
ITEMS *items = NULL;
int num_items = process(&items);
for (int i = 0; i < num_items; i++)
{
printf("%d - %s - %s\n", items[i].number, items[i].name, items[i].description);
}
return 0;
}
With better error detection
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct items
{
int number;
char *name;
char *description;
} ITEMS;
int process(ITEMS **items)
{
ITEMS *temp = NULL;
int i = 0;
// Growing the array of struct
if ( NULL == ( temp = realloc(*items, (i + 1) * sizeof(**items)))) {
fprintf ( stderr, "realloc problem\n");
return i;
}
*items = temp;
// repeating this step in a loop of adding items
// Adding items here
(*items)[i].number = 72;
(*items)[i].name = strdup( "Some name"); // it comes from a variable
(*items)[i].description = strdup ("Some text");
i++;
if ( NULL == ( temp = realloc(*items, (i + 1) * sizeof(**items)))) {
fprintf ( stderr, "realloc problem\n");
return i;
}
*items = temp;
// another item
(*items)[i].number = 88;
(*items)[i].name = strdup( "Some name"); // it comes from a variable
(*items)[i].description = strdup ("Some text");
i++;
return i;
}
int main()
{
ITEMS *items = NULL;
int num_items = process(&items);
for (int i = 0; i < num_items; i++)
{
printf("%d - %s - %s\n", items[i].number, items[i].name, items[i].description);
}
return 0;
}
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;
}
This function is a part of program which will gain statistics about books (amount of specific letters, words etc.). Thing is that segmentation fault appears when trying to malloc:
*wordArray[arrayIndex] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
after reallocing whole array
*wordArray = realloc(*wordArray, (arrayIndex+1)*sizeof(**wordArray));
I know that realloc isn't really efficent but the most important thing at the moment is to understand why it doesn't work at all. Thanks a lot.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <wctype.h>
#include <wchar.h>
#define X 2
void wordManager(wchar_t ***, int **, wchar_t *);
int main(int argc, char **argv){
setlocale(LC_ALL, "");
wchar_t **wordArray;
int *wordAmount;
wchar_t word[50];
for(int i=0; i<X; i++){
scanf("%ls", word);
wordManager(&wordArray, &wordAmount, word);
}
for(int i=0; i<X; i++){
printf("%ls; %d times\n", wordArray[i], wordAmount[i]);
}
}
void wordManager(wchar_t ***wordArray, int **wordAmount, wchar_t *newWord){
static int isArrayInitialised = 0;
static int isArrayEmpty = 1;
static int arrayIndex = 0;
int wordLocation;
if(!isArrayInitialised){
*wordArray = malloc(sizeof(**wordArray)*1);
if(*wordArray==NULL){
printf("Error mallocing wordArray");
exit(EXIT_FAILURE);
}
*wordAmount = calloc(1, sizeof(*wordAmount));
if(*wordAmount==NULL){
printf("Error callocing wordAmount");
exit(EXIT_FAILURE);
}
isArrayInitialised = 1;
}
if(isArrayEmpty){
*wordArray[0] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
wcscpy(*wordArray[0], newWord);
*wordAmount[0] = 1;
isArrayEmpty = 0;
}
else{
//Check if word is already in an array.
wordLocation = 0;
for(; wordLocation<arrayIndex+1; wordLocation++){
if(!wcscmp(*wordArray[wordLocation], newWord)) break;
}
printf("%d\n", wordLocation);
//Word hasn't been found. Then:
if(wordLocation==arrayIndex+1){
arrayIndex++; //Increase arrays' volume.
*wordArray = realloc(*wordArray, (arrayIndex+1)*sizeof(**wordArray));
if(*wordArray==NULL){
printf("Error reallocating wordArray memory.\n Array index: %d", arrayIndex);
exit(EXIT_FAILURE);
}
*wordAmount = realloc(*wordAmount, (arrayIndex+1)*sizeof(**wordAmount));
if(*wordAmount==NULL){
printf("Error reallocating wordAmount memory.\n Array index: %d", arrayIndex);
exit(EXIT_FAILURE);
}
*wordArray[arrayIndex] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
wcscpy(*wordArray[arrayIndex], newWord);
*wordAmount[arrayIndex] = 1;
}
//Word has been found in an array.
else{
(*wordAmount[wordLocation])++;
}
}
}
I am having an error with the code we are using, was wondering if someone could help debug. Seems like we are getting a malloc error. Thanks.
void readWords(char norm_word[MAXSIZE], Word ** array) {
int i = 0;
bool found = false;
int result = 0;
Word * current_pointer = malloc (sizeof(Word*));//creates a temporary variable for each pointer in the array
for (i=0; i<word_counter; i++) {
current_pointer = *(array+i); //accesses the current pointer
result = strcmp(norm_word, (current_pointer -> word)); //compares the string to each stored string
if (result == 0) {
found = true;
(current_pointer->freq)++;
break;
}
}
if(!found) {
if(pointer_counter == word_counter) {
array = realloc(array, sizeof(array)*2);
pointer_counter*=2;
}
Word * new_pointer = (Word*) malloc (sizeof(Word*));
strcpy(new_pointer -> word, norm_word);
*(array + (pointer_counter - 1)) = new_pointer;
word_counter++;
}
;
}
All pointers have the same size on your system. So a sizeof always returns the same size for any pointer. You want to allocate for the structure, so you need to use sizeof on the name without the star. malloc will return the pointer to that block of memory afterwards.
Here is a short implementation:
#include <iostream>
#include <string>
typedef struct
{
int num;
int numnum;
}numbers;
int main(int argc, char ** argv)
{
numbers* n = (numbers*)malloc(sizeof(numbers));
n->num = 1;
n->numnum = 2;
free(n);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAXSIZE 64
typedef struct word {
char word[MAXSIZE];
int freq;
} Word;
int word_counter = 0;
size_t pointer_counter = 16;//Number of pointers that ensure
void readWords(char norm_word[MAXSIZE], Word ** array) {
int i = 0;
bool found = false;
Word *current_pointer = *array;
for (i=0; i<word_counter; i++) {
if(strcmp(norm_word, current_pointer->word) == 0){
found = true;
current_pointer->freq++;
break;
}
++current_pointer;
}
if(!found) {
if(pointer_counter == word_counter) {
pointer_counter *= 2;
*array = realloc(*array, sizeof(Word)*pointer_counter);
}
Word *new_pointer = *array + word_counter;
new_pointer->freq = 1;
strcpy(new_pointer->word, norm_word);
++word_counter;
}
}
int main(void){
Word *vocabulary = calloc(pointer_counter, sizeof(Word));
char norm_word[MAXSIZE];
while(1==scanf("%s", norm_word)){
readWords(norm_word, &vocabulary);
}
{
int i;
for(i = 0; i < word_counter; ++i){
printf("%s(%d)\n", vocabulary[i].word, vocabulary[i].freq);
}
}
free(vocabulary);
return 0;
}
Can anyone give me some indication as to why array of structs doesn't print out properly ?
I think its something to do with the memory I have allocated to the struct I am unsure !!
Using mac osx mountain lion xcode 4 gcc
Thanks for any help completely stuck!!
(Please have patience I am only a student !)
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
typedef struct{
char* one;
char* two;
} Node;
Node *nodes;
int count = 0;
//-----------------------------------------------------------------------
void add(char *one,char*two){
char x[40];
char y[40];
printf("reached..\n");
strcpy(x,one);
strcpy(y,two);
printf("--> X: %s\n",x);
printf("--> Y: %s\n",y);
Node newNode;
newNode.one = x;
newNode.two = y;
nodes[count]= newNode;
count++;
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
void print(){
int x;
for (x = 0; x < 10; x++)
{
printf("%d : (%s, %s) \n",x,nodes[x].one, nodes[x].two);
}
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
void check(char **arg)
{
if(strcmp(*arg, "Add") == 0)
{
add(arg[1],arg[2]);
}else if(strcmp(*arg,"print") == 0)
{
print();
}else{
printf("Error syntax Enter either: \n Add [item1][item2]\n OR \n print\n");
}
}
//-----------------------------------------------------------------------
void readandParseInput(char *line,char **arg)
{
if (fgets (line, 512, stdin)!= NULL) {
char * pch;
pch = strtok (line," \n\t");
int count = 0;
arg[0] = pch;
while (pch != NULL)
{
count++;
pch = strtok (NULL, " \n\t");
arg[count] =pch;
}
}else{
printf("\n");
exit(0);
}
}
//-----------------------------------------------------------------------
int main()
{
int size = 100;
nodes = calloc(size, sizeof(Node));
int i;
for(i = 0;i <100; i++){
printf("%s , %s \n",nodes[i].one,nodes[i].two );
// nodes[i].one = ".";
// nodes[i].two = ".";
}
char line[512]; /* the input line */
char *arg[50]; /* the command line argument */
while (1)
{
readandParseInput(line,arg);
if(arg[0] != NULL){
check(arg);
}
}
return(0);
}
You're keeping pointers to the following automatic variables:
char x[40];
char y[40];
These go out of scope when add() returns, leaving you with dangling pointers.
You either have to turn Node::one and Node::two into arrays, or allocate memory for them on the heap.
In you add() function, you cannot assign one struct to another via an = operator... you would have to copy it...
memcpy( &nodes[count], &newNode )
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char *fn;
}NAME;
#define NAME_LEN 20
int main()
{
NAME name;
name.fn = (char *) calloc(NAME_LEN, sizeof(char));
strcpy(name.fn, "Namco");
printf("Name: %s\n", name.fn);
free(name.fn);
return 0;
}
you can't just assign a string like this in c
newNode.one = x;
newNode.two = y;
what is newNode.one referring to???
at Function add
newNode.one = x;
newNode.two = y;
to
newNode.one = strdup(x);
newNode.two = strdup(y);