I am trying to allocate enough space for an array of pointers to structure(City) with
City **ptrArray = (City **)calloc(numberOfLines, sizeof(City*));
char tempArray[100];
char* temp = tempArray;
int slength;
for (int i = 0; i < numberOfLines; i++)
{ //Allocates enough memory for array of length of string
fscanf(fPtr, "%99[^:] %*c", tempArray);
slength = strlen(temp);
ptrArray[i] = (City*)malloc(sizeof(int)+(sizeof(char)*slength));
strcpy(ptrArray[i]->cityName, temp);
//fscanf(fPtr, "%d", ptrArray[i]->temperature);
}
This is where I read the data from a file into the array. The debugger(visual studio) only shows one cell in ptrArray and it seems that the data gets lost.
numberOfLines is an assigned int value.
tempArray is a temporary holding place for the strings read from the file.
temp is a pointer to tempArray.
Bonus issue: The commented out line at the bottom of the for loop breaks the code every time and I have no clue why.
edit: I added the code where I initialized temp and tempArray.
Also it is a weird call to malloc because the assignment specifies allocating exactly enough memory for the string and an int instead of having a maximum value for the string. And here is my struct
typedef struct{
int temperature;
char cityName[100];
}City;
Thank you very much for you help!
For dynamic allocation of cityName.
typedef struct{
int temperature;
char *cityName;// pointer to char
}City;
City **ptrArray = calloc(numberOfLines, sizeof(City*));
if ( ptrArray == NULL) {
printf ( "calloc failed\n");
exit(1);
}
char tempArray[100];
int slength;
for (int i = 0; i < numberOfLines; i++)
{
if ( ( fscanf(fPtr, "%99[^:] %*c", tempArray)) != 1) {
//handle problem - break or return or exit.
}
slength = strlen(tempArray);
ptrArray[i] = malloc( sizeof(City));// memory for structure
if ( ptrArray[i] == NULL) {
printf ( "malloc failed\n");
exit ( 1);
}
ptrArray[i]->cityName = malloc( 1 + slength));// memory for cityName + 1 for '\0'
if ( ptrArray[i]->cityName == NULL) {
printf ( "malloc failed\n");
exit (1);
}
strcpy(ptrArray[i]->cityName, tempArray);
if ( ( fscanf(fPtr, "%d", &ptrArray[i]->temperature)) != 1) {
//handle problem break or return or exit
}
}
Memory allocated should also be freed when it is no longer needed. numberOfLines and ptrArray may have different names outside this function and the corresponding names would be used instead.
for ( i = 0; i < numberOfLines; i++) {
free ( ptrArray[i]->cityName);
free ( ptrArray[i]);
}
free ( ptrArray);
Related
I'm new to C, so please forgive me for noobie mistakes, we all need to start somewhere.
My task is to get some lines from a big file and store each line in a 2d array, where li[0] is the first line and so on...
On top of that, I have no ideia whats the size of this 'big text', so I came up with the code bellow to resize the array every time it reaches critical size (is there an easier way to do that?). Also, I could not find a better way to define the line size other than setting it very high.
The code bellow fails on the second time it resizes with an exception on this line char **temp = realloc(lin, LINE_QUANT * sizeof(char*));
Whats causing that exception?
#include <stdio.h>
#include <stdlib.h>
#define LINE_TAM 200
size_t PAL_QUANT = 100, LINE_QUANT = 3;
int main(){
int i = 0;
char **li = (char**) malloc(LINE_QUANT * sizeof(char*));
char fname[30];
FILE *arq = NULL;
// alloc word container
for (i=0; i < LINE_QUANT; i++)
li[i] = malloc(LINE_TAM * sizeof(char));
if(li == NULL) return 0;
//(ommited file opener)
i = 0;
//getting words from file (unknown size)
while(fgets(li[i], LINE_TAM, arq) != NULL){
while(i >= LINE_QUANT - 1) resizeArr(li);
i++;
}
return 1;
}
void resizeArr(char **lin){
int i;
LINE_QUANT = LINE_QUANT * 2;
char **temp = realloc(lin, LINE_QUANT * sizeof(char*));
if(temp) {
lin = temp;
for (i = LINE_QUANT/2; i < LINE_QUANT; i++){
lin[i] = malloc(LINE_TAM * sizeof(char*));
if (lin[i] == NULL)
exit(1);
}
}
else
exit(1);
free(temp);
}
Since each element of the array will be the same size, use could be made of a pointer to array, (*li)[LINE_TAM].
Because resizeArr modifies the pointer, either a pointer to the pointer needs to be passed to the function or the function needs to return the pointer.
realloc will take care of any required free, so do not free the pointers.
This uses stdin but it can be modified to use a FILE*.
Enter stop to exit the loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE_TAM 200
void resizeArr ( size_t *line_quant, char (**lin)[LINE_TAM]);
int main(){
int i = 0;
char (*li)[LINE_TAM] = NULL;//pointer to array
size_t Line_Quant = 3;
// alloc word container
if ( NULL == ( li = malloc( sizeof *li * Line_Quant))) {
fprintf ( stderr, "malloc problem\n");
return 1;
}
i = 0;
//getting words from file (unknown size)
while ( fgets ( li[i], LINE_TAM, stdin) != NULL) {
if ( 0 == strcmp ( li[i], "stop\n")) {
break;
}
if (i >= Line_Quant - 1) {
resizeArr ( &Line_Quant, &li);
}
i++;
}
free ( li);
return 1;
}
void resizeArr ( size_t *line_quant, char (**lin)[LINE_TAM]) {
int i;
char (*temp)[LINE_TAM] = realloc ( *lin, sizeof **lin * *line_quant * 2);
if ( temp) {//success
*lin = temp;//assign back to caller
*line_quant *= 2;//increase by two
for ( i = *line_quant / 2; i < *line_quant; i++) {
(*lin)[i][0] = 0;
}
}
else {
fprintf ( stderr, "realloc problem\n");
}
}
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define stock_dir "/Users/myname/prices/"
#define file_list "/Users/myname/trade/trade/nasdaq100_stock_list.txt"
#define look_back_period 3
#define num_stocks 103
#define days_of_data 21
int main()
{
FILE *stocks, *stk;
char stock[11], fullpath[50] = "\0", header[25];
char line_of_data[40];
char *sclose, *svol;
int n = 0, i = 0;
typedef struct daily_data {
char *date;
float close;
int vol;
}data;
sclose = (char*) malloc(20*sizeof(char));
svol = (char*) malloc(20*sizeof(char));
data** day_data = (data**) malloc(num_stocks*sizeof(data*) );
if (day_data == NULL)
{
printf("day_data not allocated\n");
exit(0);
}
for(i = 0; i < num_stocks; i++)
if ((day_data[i] = (data*)malloc(days_of_data*sizeof(data))) == NULL)
{
printf("data[%d] not allocated\n", i);
exit(0);
}
for(i = 0; i < num_stocks; i++)
for(n = 0; n < days_of_data; n++)
if ((day_data[i][n].date = (char*)malloc(20)) == NULL)
{ printf("data[%d][%d] not allocated\n", i,n);
exit(0);
}
/* ... code omitted ... */
if ( (stocks = fopen(file_list, "r") )== NULL)
printf("didn't open file list\n");
i = 0;
while (fgets(stock, sizeof(stock), stocks) != NULL)
{
printf("%s",stock);
strcpy(fullpath,stock_dir);
strcat(fullpath,stock);
fullpath[strcspn(fullpath, "\n")] = 0;
if ( (stk = fopen(fullpath, "r") )== NULL)
printf("didn't open quote list\n");
fgets(header,sizeof(header),stk);
n=0;
while(fgets(line_of_data, sizeof(line_of_data),stk) !=NULL)
{
fgets(line_of_data,sizeof(line_of_data),stk);
day_data[i][n].date = strtok(line_of_data, ",");
sclose = strtok(NULL,",");
day_data[i][n].close = atof(sclose);
svol = strtok(NULL, ",");
day_data[i][n].vol = atoi(svol);;
printf("%s %f %d\n",day_data[i][n].date,day_data[i][n].close,day_data[i][n].vol);
n++;
}
fclose(stk);
i++;
}
for (n = look_back_period - 1; n < (days_of_data - look_back_period); n++)
printf("%d %s %f %d\n",n, day_data[1][n].date, day_data[1][n].close, day_data[1][n].vol);
}
The print statement in the while(fgets(line_of_data, sizeof(line_of_data),stk) !=NULL) loop shows that everything went into the right place. But when I print values outside they're mostly wrong. I'm supposed to add more details but I don't know what else to say. I lose the values in the struct when I leave the loop.
You overwrite the same data again and again.
Take a look at your structure:
typedef struct daily_data {
char *date; ///< a pointer without own storage
float close;
int vol;
}data;
while processing your file you read each line into line_of_data
while(fgets(line_of_data, sizeof(line_of_data),stk) !=NULL)
you tokenize the line_data and assign the pointer to data->date
day_data[i][n].date = strtok(line_of_data, ",");
What tokenize (strtok reference) does is inserting terminators into your input string and returning the pointer to the start of the new part of your input. So no new memory is allocated at this point. the returned pointer points into your input string.
So effectively you assigning the local variable pointer to your data storage structure.
Additionally to this you lose the pointer to your initially allocated memory for the date pointer.
I would suggest you to remove the a priory allocation of date and allocate the required memory at the point you really know the required length or if you are sure, you know the maximum length, then you can just make the date member an array.
So you either have to allocate new memory and copy the tokenized data or if you made date a fixed size array, just copy the tokenized data.
on the first variant it would look like this
char * tok = strtok(line_of_data, ",");
day_data[i][n].date = malloc(strlen(tok)+1);
strcpy(day_data[i][n].date, tok);
(+ remove the pre allocation of the date member)
or the second variant:
change data to
typedef struct daily_data {
char date[20];
float close;
int vol;
}data;
and the processing code looks like this:
char * tok = strtok(line_of_data, ",");
strcpy(day_data[i][n].date, tok);
(+ (of course) remove the pre allocation of the date member)
You also should in any case add error handling if the tokenized string exceeds the max length or the format of the lines does not match the expectation (missing delimiters, wrong/invalid number(formats), ...).
I have string array initialized like that:
char ** strArray;
if ( (strArray = malloc(sizeof(*strArray) + 3)) == NULL ) {
fprintf(stderr, "ls1: couldn't allocate memory");
//exit(EXIT_FAILURE);
}
strArray[0] = NULL;
strArray[0] = "111";
strArray[1] = "222";
strArray[2] = "1";
strArray[3] = "2";
I want to convert this string array to int array, like that:
int * toIntArray(char ** strArray) {
int size = getCharArraySize(strArray);
int intArray[size];
int i;
for ( i = 0; i < size ; ++i)
{
intArray[i] = atoi(strArray[i]);
printf( "r[%d] = %d\n", i, intArray[i]);
}
intArray[size] = '\0';
return intArray;
}
int getCharArraySize(char ** strArray) {
int s = 0;
while ( strArray[s]) {
printf("Char array: %s.\n", strArray[s]);
s++;
}
return s;
}
And then I want to sort this int array.
I must have string array initilized like above (char ** strArray) and then convert this to int array and then sort it. Can anybody help my with that? I would ask about printed sorted integer in main function.
A few minor things to take note of in the question code:
char ** strArray;
if ( (strArray = malloc(sizeof(*strArray) + 3)) == NULL ) {
fprintf(stderr, "ls1: couldn't allocate memory");
//exit(EXIT_FAILURE);
}
If successful, the intention of the above code allocates memory to strArray sufficient for three char *'s. Specifically, strArray[0], strArray1 and strArray[2].
NOTE: As pointed out in Matt McNabb's comment below, it actually incorrectly allocates memory sufficient for one char *, and three extra bytes.
strArray[0] = NULL;
The above line sets sets the first pointer in the **strArray to point at NULL.
strArray[0] = "111";
The above code is odd. After just setting strArray[0] to point at NULL, the above line changes it to point to "111". Kind of makes setting it to NULL (in the first place) seem unnecessary.
strArray[1] = "222";
strArray[2] = "1";
The above two lines initialize the other two pointers in the strArray correctly.
strArray[3] = "2";
The above line attempts to initialize strArray[3], when that element of the array really doesn't exist. So, it is changing something to point to "2", but probably not with the expected result.
Perhaps the intent would be better served by changing the above code to:
char **strArray;
size_t strArrayElements=4;
if(NULL == (strArray = malloc((strArrayElements+1) * sizeof(*strArray))))
{
fprintf(stderr, "ls1: couldn't allocate memory");
exit(EXIT_FAILURE);
}
strArray[strArrayElements] = NULL;
strArray[0] = "111";
strArray[1] = "222";
strArray[2] = "1";
strArray[3] = "2";
As can be observed, the above code allocates 5 elements (strArrayElements+1) to the **strArray. The last element strArray[4] is initialized to NULL; a marker to indicate End-Of-List. Then the other 4 elements [0..3] are initialized.
Now shifting focus to:
int * toIntArray(char ** strArray) {
int size = getCharArraySize(strArray);
int intArray[size];
int i;
for ( i = 0; i < size ; ++i)
{
intArray[i] = atoi(strArray[i]);
printf( "r[%d] = %d\n", i, intArray[i]);
}
intArray[size] = '\0';
return intArray;
}
The above code is successful at converting the strings to their integer forms, and storing them in intArray. However, the code is flawed when it attempts to return intArray to the caller. The intArray variable was declared as a local stack object. The return statement causes all such stack variables to become invalid; and allows the stack memory such variables were using to be used for other things.
Perhaps the the following code better represents what was intended. It allocates memory from the heap for intArray. This allocated memory can outlive the return statement:
int *toIntArray(char **strArray)
{
int size = getCharArraySize(strArray);
int *intArray = malloc(size * sizeof(*intArray));
int i;
for ( i = 0; i < size ; ++i)
{
intArray[i] = atoi(strArray[i]);
printf( "r[%d] = %d\n", i, intArray[i]);
}
intArray[size] = '\0';
return(intArray);
}
Spoiler code may be found here.
I'm working on a homework assignment and I need to basically create a character buffer. One of the functions I need to create is called "b_reset". It's purpose is to reinitialize the given buffer so that it will point to the first position in the char buffer. This is needed because later on, when a new char is added to the buffer, it needs to be added to the first position in the buffer.
This is the code I have thus far:
The struct:
typedef struct BufferDescriptor {
char * ca_head ;
int capacity ;
char inc_factor;
int addc_offset ;
int mark_offset ;
char r_flag;
char mode;
} Buffer ;
The code:
int b_reset ( Buffer *pB )
{
Buffer *temp = NULL;
int i = 0;
int j = 1;
if (pB == NULL)
{
return R_FAIL_1;
}
else
{
temp = (Buffer*)malloc(sizeof(Buffer*));
if (temp == NULL)
{
return R_FAIL_1;
}
temp->ca_head = (char*)malloc(pB->capacity);
if (!temp->ca_head)
{
temp = NULL;
return R_FAIL_1;
}
for(i = 0;i < ca_getsize(pB);++i)
{
temp->ca_head[j] = pB->ca_head[i];
j++;
}
pB->ca_head = temp->ca_head;
//free(temp->ca_head);
//free(temp);
return 0;
}
}
My goal in this code was to create a temporary buffer that would basically shift over everything 1 time based on the actual given buffer. This would make the first position empty so another char could be added.
The problem I'm running into is that the original buffer doesn't seem to be returning the right values after I reset it.
When I do this for example:
temp->ca_head[0] = 'a';
temp->ca_head[1] = 'b';
temp->ca_head[2] = 'c';
temp->ca_head[3] = 'd';
temp->ca_head[4] = 'e';
b_reset(temp); //this will return the size as 0, when it's actually 5
//temp->ca_head[0] = 'i'; //if this is executed, it returns the size as 6
//and prints out the right values, but if it's not,
//it will not print out anything
printf("%d", ca_getsize(temp));
for(i = 0;i < ca_getsize(temp);++i)
{
printf("%c", temp->ca_head[i]);
}
I know something is going wrong here, but I'm not too sure what. Any suggestions would be greatly appreciated.
This code is based on your followup comment:
well I'm not trying to resize the buffer, I just want to create an
empty space in the first position, so basically shifting everything to
the right 1 time. The assumption is that there is a enough space in
the buffer to handle this process.
I don't think you need to do any malloc() ing beyond the initial one. You can just shift everything up in a loop:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define R_FAIL_1 1
#define BUFFER_SIZE 10
typedef struct BufferDescriptor {
char * ca_head ;
int capacity ;
char inc_factor;
int addc_offset ;
int mark_offset ;
char r_flag;
char mode;
} Buffer ;
void allocate_buffer(Buffer *pB, int size)
{
pB->ca_head = malloc(size);
assert(pB->ca_head);
pB->capacity = size;
}
int ca_getsize( Buffer *pB)
{
return pB->capacity;
}
int b_reset ( Buffer *pB )
{
int i = 0;
if (pB == NULL)
{
return R_FAIL_1;
}
else
{
if ( ca_getsize(pB) <= 0 || pB->ca_head == NULL )
return R_FAIL_1;
}
// shift data up by 1 byte
for( i = ca_getsize(pB) - 1 ; i > 0;i-- )
{
pB->ca_head[i] = pB->ca_head[i-1];
}
pB->ca_head[0] = '\0';
return 0;
}
void print_buffer(Buffer *pB)
{
printf("capacity: %d \n", ca_getsize(pB));
for (int i = 0;i < ca_getsize(pB);++i)
{
printf("buffer(%d): [%d] ",i, pB->ca_head[i]);
}
printf("\n");
}
int main(void)
{
Buffer a_buffer;
allocate_buffer(&a_buffer,BUFFER_SIZE);
strcpy(a_buffer.ca_head,"abcdefgh");
print_buffer(&a_buffer);
int ret = b_reset(&a_buffer);
assert(ret == 0);
print_buffer(&a_buffer);
}
temp = (Buffer*)malloc(sizeof(Buffer*));
You need to allocate enough space to hold a Buffer, but you only allocate enough space to hold a pointer to a buffer. This should be:
temp = (Buffer*)malloc(sizeof(Buffer));
You are managing your memory incorrectly. You are allocating memory for a new Buffer struct when actually you only need to handle the memory of the ca_head member (if my interpretation of your homework problem is correct).
Each time you invoke b_reset, you will allocate memory for this struct that will not be released. If you don't handle your memory correctly, you will experience unexpected results as the one you are reporting in your question.
I suggest you to make a research on the function realloc and use it properly in your b_reset function.
Good luck with your homework.
ok, heres my code. I'm trying to pass an array of pointers to a structure to a function.
I need to dynamically allocate each structure and put a pointer to that structure in the array.
When I malloc the second time thru it gets a heap error.
HELP
#define MAXSTRUCTS 50
#define MAXBUFF 100
typedef struct {
char fullName[41];
char address[41];
char cityState[41];
char zipcode[11];
} Persons;
int readData(Persons *structPtrs[]);
int main(void) {
int totalStructs;
Persons *structPtrs[MAXSTRUCTS];
totalStructs = 0;
structPtrs[0] = NULL;
totalStructs = readData(structPtrs);
}
int readData(Persons *strptr[]) {
int tStructs = 0;
int recs;
char inRecord[MAXBUFF];
Persons *tmpPtr;
tStructs = 0;
for (recs=0; recs < MAXSTRUCTS; recs++) {
if (gets(inRecord) != NULL) {
strptr[recs] = (Persons *)malloc( sizeof(Persons));
tmpPtr = strptr[recs];
strncpy(tmpPtr->fullName,inRecord,MAXBUFF);
gets(inRecord);
strncpy(tmpPtr->address,inRecord,MAXBUFF);
gets(inRecord);
strncpy(tmpPtr->cityState,inRecord,MAXBUFF);
gets(inRecord);
strncpy(tmpPtr->zipcode,inRecord,MAXBUFF);
strptr[recs] = tmpPtr;
tStructs++;
}
else {
if ( recs = 0 ) {
exit (0);
}
recs=MAXSTRUCTS;
}
}
return(tStructs);
}
You are doing everything right in regard of passing an array of pointers and allocating memory. What leading to a heap corruption is incorrect usage of strncpy function. The arrays where you are trying to copy data to are slightly smaller than MAXBUFF in all cases. To fix this, you have to specify the size of destination array instead of MAXBUFF. For example, instead of:
strncpy(tmpPtr->fullName,inRecord,MAXBUFF);
... do (assuming that buffer is already filled with \0 symbols):
strncpy(tmpPtr->fullName,inRecord, sizeof(tmpPtr->fullName) - 1);
Also, using gets function is not recommended as well as it could easily lead to buffer overruns. Try using fgets instead.
Here is your modified example that works:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAXSTRUCTS 2
#define MAXBUFF 100
typedef struct {
char fullName[41];
char address[41];
char cityState[41];
char zipcode[11];
} Persons;
int readData(Persons *structPtrs[]);
int main ()
{
int totalStructs;
int recs;
Persons *structPtrs[MAXSTRUCTS];
totalStructs = 0;
structPtrs[0] = NULL;
totalStructs = readData(structPtrs);
for(recs = 0; recs < totalStructs; ++recs) {
printf ("Record #%d - %s\n", recs + 1, structPtrs[recs]->fullName);
}
return 0;
}
int readData(Persons *strptr[])
{
int tStructs = 0;
int recs;
char inRecord[MAXBUFF];
Persons *tmpPtr;
tStructs = 0;
for (recs=0; recs < MAXSTRUCTS; ++recs) {
memset (inRecord, 0, sizeof(inRecord));
if (fgets(inRecord, sizeof (inRecord) - 1, stdin))
{
strptr[recs] = (Persons *)malloc(sizeof(Persons));
tmpPtr = strptr[recs];
memset (tmpPtr, 0, sizeof(Persons));
strncpy(tmpPtr->fullName,inRecord,sizeof(tmpPtr->fullName) - 1);
fgets(inRecord, sizeof (inRecord) - 1, stdin);
strncpy(tmpPtr->address,inRecord,sizeof(tmpPtr->address) - 1);
fgets(inRecord, sizeof (inRecord) - 1, stdin);
strncpy(tmpPtr->cityState,inRecord, sizeof(tmpPtr->cityState) - 1);
fgets(inRecord, sizeof (inRecord) - 1, stdin);
strncpy(tmpPtr->zipcode,inRecord, sizeof (tmpPtr->zipcode) - 1);
strptr[recs] = tmpPtr;
tStructs++;
} else {
if ( recs = 0 ) {
exit (0);
}
recs=MAXSTRUCTS;
}
}
return(tStructs);
}
int readDataToRecord( Persons *eachEntry[] ) {
int numEntries = 0 ;
Persons *tempPtr ;
for( int i=0 ; i < NUM_OF_RECORDS; ++i ) {
eachEntry[i] = ( Record * ) malloc( sizeof( Record ) ) ;
memset( eachEntry[i], 0, sizeof( Record ) ) ;
tempPtr = eachEntry[i] ;
fgets( tempPtr->firstName, sizeof( tempPtr->firstName ), stdin ) ;
fgets( tempPtr->secondName, sizeof( tempPtr->secondName), stdin ) ;
eachEntry[i] = tempPtr ;
++numEntries ;
}
return numEntries ;
}
This would also efficiently do the job. Once you have new record, you would any how have the memory allocated for each of its member. So you can directly fgets to that variable.
#Vlad : Please let me know if I am wrong.