Why do the values in the array change after exiting the loop? - c

After exiting the while loop for some reason the values in the array change but I'm not why. Inside the loop the values are correct and they store inside the array (a) normally. This is in c!
int * readFile()
{
char file_name[50];
printf("Enter the name of the file to open:\n");
scanf("%s",file_name);
FILE *fp;
fp = fopen(file_name,"r");
if(fp == NULL )
{
printf("Sorry but the File you entered cannot be opened\n");
int *b;
b[0] = -1;
return b;
}
int *a;
int j=0;
long int value=0;
while (fscanf(fp,"%d",&value)!=EOF) {
if((a =malloc(sizeof(long int))) == NULL)
printf("not enough memory\n");
a[j]=value;
j++;
}
printf("%d %d %d\n",a[0],a[1],a[2]);
int i=0;
for(i=0; i<j;i++)
{
printf("array[%d] = %d\n",i,a[i]);
}
fclose(fp);
return a;
}
Any help would be greatly appreciated!

When you do if((a =malloc(sizeof(long int))) == NULL) you are only allocating enough memory for a single long int ( 32 bits in size), but you need to allocate memory for each int that you plan to store. Because malloc allocates a single block of memory, you need to know how many ints you plan to store before hand. If you don't mind the overhead, you can do a preliminary run through the file being read and count the number of ints you will read (basically your j variable) , then you can do
a =malloc( intCounter * sizeof(long int))) == NULL , where intCounter would be the total number of integers in the file (j).
Another option would be to use a linked list,(which is close to what your trying to do) where you can allocate memory for each int on the fly, but you will need to store pointer information to the next node in the array.
The malloc call in the while loop overwrites the data that was stored in the single allocation of an Int. For example if you read 1 2 3 from the text file it would store 1 in the a, malloc different memory adress to a, store 2, malloc yet another memory address and store 3. Resulting in 0 , 0 , 3 to be printed.

You have used a mix of int and long int throughout your code. You need to settle on a consistent type; for my answer I've gone with int. (You could easily go through and change all occurrences of int to long though, so long as you also change the fscanf format string to %ld).
Currently you allocate a new block of one long int each time around the loop. As well as leaking memory from previous loop iterations, you access out of bounds of this. Also, when malloc fails you print a message and keep going!
Instead you need to allocate a single block which will hold several integers. One way to do this is by using the realloc function to make the existing allocation bigger.
Also, when checking the return value of fscanf, you should check for == 1 here. It will return 0 if they typed in some letters but did not trigger EOF condition, and so your program will go on forever.
Here is how that loop could look like:
int *a = NULL;
size_t j = 0;
while ( fscanf(fp,"%d",&value) == 1 )
{
int *ptr = realloc( a, (j+1) * sizeof *a );
if ( !ptr )
{
printf("not enough memory\n");
break;
}
a = ptr;
a[j]=value;
j++;
}
By using a separate variable ptr for the new allocation, we can recover from out-of-memory condition (the program can continue working with the number of ints that were input so far).
If you intend to handle out-of-memory by immediately exiting the program (e.g. by calling exit(EXIT_FAILURE); instead of break; then you could shorten your code a bit by using a = realloc( a, etc. instead of ptr.
The earlier code int *b; b[0] = -1; has a problem: b doesn't point anywhere but you write through it.
This function has a design problem in that the caller has no way of knowing what j was. One solution to this would be to always put -1 on the end of the input (this idea is called "sentinel value" - and remember to allocate space for it); another option would be to have an "out" parameter to the function.

Related

Abort trap: 6 error with arrays in c

The following code compiled fine yesterday for a while, started giving the abort trap: 6 error at one point, then worked fine again for a while, and again started giving the same error. All the answers I've looked up deal with strings of some fixed specified length. I'm not very experienced in programming so any help as to why this is happening is appreciated. (The code is for computing the Zeckendorf representation.)
If I simply use printf to print the digits one by one instead of using strings the code works fine.
#include <string.h>
// helper function to compute the largest fibonacci number <= n
// this works fine
void maxfib(int n, int *index, int *fib) {
int fib1 = 0;
int fib2 = 1;
int new = fib1 + fib2;
*index = 2;
while (new <= n) {
fib1 = fib2;
fib2 = new;
new = fib1 + fib2;
(*index)++;
if (new == n) {
*fib = new;
}
}
*fib = fib2;
(*index)--;
}
char *zeckendorf(int n) {
int index;
int newindex;
int fib;
char *ans = ""; // I'm guessing the error is coming from here
while (n > 0) {
maxfib(n, &index, &fib);
n -= fib;
maxfib(n, &newindex, &fib);
strcat(ans, "1");
for (int j = index - 1; j > newindex; j--) {
strcat(ans, "0");
}
}
return ans;
}
Your guess is quite correct:
char *ans = ""; // I'm guessing the error is coming from here
That makes ans point to a read-only array of one character, whose only element is the string terminator. Trying to append to this will write out of bounds and give you undefined behavior.
One solution is to dynamically allocate memory for the string, and if you don't know the size beforehand then you need to reallocate to increase the size. If you do this, don't forget to add space for the string terminator, and to free the memory once you're done with it.
Basically, you have two approaches when you want to receive a string from function in C
Caller allocates buffer (either statically or dynamically) and passes it to the callee as a pointer and size. Callee writes data to buffer. If it fits, it returns success as a status. If it does not fit, returns error. You may decide that in such case either buffer is untouched or it contains all data fitting in the size. You can choose whatever suits you better, just document it properly for future users (including you in future).
Callee allocates buffer dynamically, fills the buffer and returns pointer to the buffer. Caller must free the memory to avoid memory leak.
In your case the zeckendorf() function can determine how much memory is needed for the string. The index of first Fibonacci number less than parameter determines the length of result. Add 1 for terminating zero and you know how much memory you need to allocate.
So, if you choose first approach, you need to pass additional two parameters to zeckendorf() function: char *buffer and int size and write to the buffer instead of ans. And you need to have some marker to know if it's first iteration of the while() loop. If it is, after maxfib(n, &index, &fib); check the condition index+1<=size. If condition is true, you can proceed with your function. If not, you can return error immediately.
For second approach initialize the ans as:
char *ans = NULL;
after maxfib(n, &index, &fib); add:
if(ans==NULL) {
ans=malloc(index+1);
}
and continue as you did. Return ans from function. Remember to call free() in caller, when result is no longer needed to avoid memory leak.
In both cases remember to write the terminating \0 to buffer.
There is also a third approach. You can declare ans as:
static char ans[20];
inside zeckendorf(). Function shall behave as in first approach, but the buffer and its size is already hardcoded. I recommend to #define BUFSIZE 20 and either declare variable as static char ans[BUFSIZE]; and use BUFSIZE when checking available size. Please be aware that it works only in single threaded environment. And every call to zeckendorf() will overwrite the previous result. Consider following code.
char *a,*b;
a=zeckendorf(10);
b=zeckendorf(15);
printf("%s\n",a);
printf("%s\n",b);
The zeckendorf() function always return the same pointer. So a and b would pointer to the same buffer, where the string for 15 would be stored. So, you either need to store the result somewhere, or do processing in proper order:
a=zeckendorf(10);
printf("%s\n",a);
b=zeckendorf(15);
printf("%s\n",b);
As a rule of thumb majority (if not all) Linux standard C library function uses either first or third approach.

Allocating large space for dynamic array

we wrote a program that reads comma-separated integer-values into an array and tries processing them with a parallel structure.
By doing so, we found out that there is a fixed limitation for the maximum size of the dynamic array, which usually gets allocated dynamically by doubling the size. Yet for a dataset with more than 5000 values, we can't double it anymore.
I am a bit confused right now, since technically, we did everything the way other posts pointed out we should do (use realloc, don't use stack but heap instead).
Note that it works fine for any file with less or equal than 5000 values.
We also tried working with realloc, but to the same result.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// compile with gcc filename -lpthread -lm -Wall -Wextra -o test
int reader(int ** array, char * name) {
FILE *fp;
int data,row,col,count,inc;
int capacity=10;
char ch;
fp=fopen(name,"r");
row=col=count=0;
while(EOF!=(inc=fscanf(fp,"%d%c", &data, &ch)) && inc == 2){
if(capacity==count)
// this is the alternative with realloc we tried. Still the same issue.
//*array=malloc(sizeof(int)*(capacity*=2));
*array = realloc(*array, sizeof(int)*(capacity*=2));
(*array)[count++] = data;
//printf("%d ", data);
if(ch == '\n'){
break;
} else if(ch != ','){
fprintf(stderr, "format error of different separator(%c) of Row at %d \n", ch, row);
break;
}
}
// close file stream
fclose(fp);
//*array=malloc( sizeof(int)*count);
*array = realloc(*array, sizeof(int)*count);
return count;
}
int main(){
int cores = 8;
pthread_t p[cores];
int *array;
int i = 0;
array=malloc(sizeof(int)*10);
// read the file
int length = reader(&array, "data_2.txt");
// clean up and exit
free(array);
return 0;
}
EDIT: I included the realloc-command we tried and changed the values back to our original testing values (starting at 10). This didn't impact the result though, or rather still does not work. Thanks anyways for pointing out the errors! I also reduced the included code to the relevant part.
I can't really get my head around the fact that it should work this way, but doesn't, so it might just be a minor mistake we overlooked.
Thanks in advance.
New answer after question has been updated
The use of realloc is wrong. Always do realloc into a new pointer and check for NULL before overwriting the old pointer.
Like:
int* tmp = realloc(....);
if (!tmp)
{
// No more memory
// do error handling
....
}
*array = tmp;
Original answer (not fully valid after question has been updated)
You have some serious problems with the current code.
In main you have:
array=malloc(sizeof(int)*10); // This only allocates memory for 10 int
int length = reader(&array, "data_1.txt");
and in reader you have:
int capacity=5001;
So you assume that the array capacity is 5001 even though you only reserved memory for 10 to start with. So you end up writing outside the reserved array (i.e. undefined behavior).
A better approach could be to handle all allocation in the function (i.e. don't do any allocation in main). If you do that you shall initialize capacity to 0 and rewrite the way capacity grows.
Further, in reader you have:
if(capacity==count)
*array=malloc(sizeof(int)*(capacity*=2));
It is wrong to use malloc as you loose all data already in the array and leak memory as well. Use realloc instead.
Finally, you have:
*array=malloc( sizeof(int)*count);
Again this is wrong for the same reason as above. If you want to resize to the exact size (aka count) use realloc

How do you iterate through a pointer?

For example:
int *start;
start = (int*)malloc(40);
If I wanted to iterate through all 40 bytes, how would I do so?
I tried doing something like:
while(start != NULL){
start++;
}
but that iterates through a massive number of values, which is much greater than 40. Thus, how do you ensure that you iterate through all 40 bytes.
Thanks for all the help.
There are two issues here.
A single ptr++ skips as many bytes as the type of element it points to.
Here the type is int, so it would skip 4 bytes each time (assuming a 32 bit machine since integer is 4 bytes (32 bits) there).
If you want to iterate through all 40 bytes (one byte at a time), iterate using say a char data type (or type cast your int* to char* and then increment)
The other problem is your loop termination.
There is no one putting a NULL at the end here, so your loop would keep running (and pointer advancing forward) until it runs into may be a null or goes out of your allotted memory area and crashes. The behavior is undefined.
If you allocated 40 bytes, you have to terminate at 40 bytes yourself.
It is worth mentioning that type casting the result of malloc is not a good idea in C. The primary reason is that it could potentially tamper a failed allocation. It is a requirement in C++ though. The details can be found in the exact same question on SO. Search "casting return value of malloc"
First of all, you should be allocating ints correctly:
int* start = malloc( sizeof( int )*40 ) ;
Then you can use array subscripting:
for( size_t i = 0 ; i < 40 ; i++ )
{
start[i] = 0 ;
}
or a pointer to the end of the allocated memory:
int* end = start+40 ;
int* iter = start ;
while( iter < end )
{
*iter= 0 ;
iter++ ;
}
Arrays represent contiguous blocks of memory. Since the name of the array is basically a pointer to the first element, you can use array notation to access the rest of the block. Remember though, there is no error checking by C on the bounds of the array, so if you walk off the end of the memory block, you can do all kinds of things that you didn't intend and more than likely will end up with some sort of memory fault or segmentation error. Since your int can be variable size, I would use this code instead:
int *start;
int i;
start = malloc(40 * sizeof(int));
for (i = 0; i < 40; i++)
{
start[i] = 0;
}
Something like that will work nicely. The way that you are doing it, at least from the code that you posted, there is no way to stop the loop because once it exceeds the memory block, it will keep going until it runs into a NULL or you get a memory fault. In other words, the loop will only exit if it runs into a null. That null may be within the block of memory that you allocated, or it may be way beyond the block.
EDIT: One thing I noticed about my code. It will allocate space for 40 ints which can be either 4 bytes, 8 bytes, or something else depending on the architecture of the machine you are working on. If you REALLY only want 40 bytes of integers, then do something like this:
int *start;
int i;
int size;
size = 40/sizeof(int);
start = malloc(size);
for (i = 0; i < size; i++)
{
start[i] = 0;
}
Or you can use a char data type or an unsigned char if you need to. One other thing that I noticed. The malloc function returns a void pointer type which is compatible with all pointers, so there is no need to do a typecast on a malloc.
Well arrays in C aren't bounded so, a few options, the most common:
int *start;
int cnt = 0;
start = (int*)malloc(sizeof(int)*40);;
while(cnt<40)
{
start++;
cnt++;
}
Another option:
int *start;
int *ref;
start = ref = (int*)malloc(sizeof(int)*40);
while(start != ref+40)
start++;
And this last one is the closest to what you seem to mean to do:
int *start;
start = ref = (int*)malloc(sizeof(int)*41);
start[40] = -1;
while((*start) != -1)
start++;
I would suggest reading more on how pointers in C work. You don't appear to have a very good grasp of it. Also, remember that C takes off the training wheels. Arrays aren't bounded or terminated in a standard way, and a pointer (address in memory) will never be NULL after iterating through an array, and the contents a pointer is pointing to could be anything.

copying an array of integers to another integer array

#include<stdio.h>
void int_copy(int* ptrA,int* ptrB,int nbr){
//int* temp = ptrB;
while(nbr != 0){
*ptrB++ = *ptrA++;
nbr--;
}
*ptrB = -1;
//ptrB = temp;
}
int main(){
int stringa[40] = {100,101,102,103,104,105,106,107,108,109,110,-1};
int stringb[40] = {0};
int *ptr;
int *ptr1;
int len = 0;
ptr = stringa;
ptr1 = stringb;
while(*ptr != -1){
*ptr++;len++;
}
printf("\n len : %d \n",len);
int_copy(stringa,stringb,len);
while(*ptr1 != -1){
printf("%d\t",*ptr1);
*ptr1++;
}
return 0;
}
I was trying out an example program to copy an array of integers to another integer array. Is there another way to do it in a more efficient way.
EDITED :
void int_copy(int* ptrA,int* ptrB,int nbr){
memcpy(ptrA,ptrB,(sizeof(int)*nbr));
}
Don't use a sentinel (-1), store the length.
Then you can use memcpy - hint: copy sizeof(int)*len bytes.
I was trying out an example program to copy an array of integers to
another integer array. Is there another way to do it in a more
efficient way.
Since this is a sample program, I'm not sure how your real program looks like. But as for allocating an array: you can either do it statically (as in your example) or dynamically using e.g. malloc(). In either way, the size of the array is known (either fixed in your source code or indirectly through the size parameter to the malloc call).
So yes, since you should know the size of the array, you can use memcpy() which is more efficient since its implementation is optimized for the architecture it runs on.
BTW: an exception could be a library that allocates the memory for you and does not provide back the length of the array. But I never came across such a situation...

How to declare an array with an arbitrary size

Ok, this is a C programming homework question. But I'm truly stuck.
I ask the user to input words, and then I insert the input into an array, but I can't have any control over the number of words the user types.
I guess what I'm asking is how do you declare a an array in C without declaring its length and without asking the user what the length should be.
I know this has something to do with malloc, but if you could give me some examples of how to do this, I would really appreciate it.
You can malloc a block of memory large enough to hold a certain number of array items.
Then, before you exceed that number, you can use realloc to make the memory block bigger.
Here's a bit of C code that shows this in action, reallocating an integer array whenever it's too small to hold the next integer.
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int *xyzzy = NULL; // Initially NULL so first realloc is a malloc.
int currsz = 0; // Current capacity.
int i;
// Add ten integers.
for (i = 0; i < 10; i++) {
// If this one will exceed capacity.
if (i >= currsz) {
// Increase capacity by four and re-allocate.
currsz += 4;
xyzzy = realloc (xyzzy, sizeof(int) * currsz);
// Should really check for failure here.
}
// Store number.
xyzzy[i] = 100 + i;
}
// Output capacity and values.
printf ("CurrSz = %d, values =", currsz);
for (i = 0; i < 10; i++) {
printf (" %d", xyzzy[i]);
}
printf ("\n");
return 0;
}
You can realloc it every time like:
int size = 0;
char **array = malloc(0);
while(/* something */)
{
char *string = // get input
size++;
array = realloc(array, size * sizeof(char*));
array[size - 1] = string;
}
Or in chunks if you care about speed.
Yes, you want malloc. Checkout this tut.
http://www.cprogramming.com/tutorial/dynamic_memory_allocation.html
This site is good in general for learning.
Here is an example of using realloc, it is basically exactly what you are asking to do.
http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/
0) obviously you will need multiple buffers, so you will need a list like structure: perhaps a record with char array 100 chars and a pointer to next structure
1) You need to capture the words char by char and store them in your buffer
2) once the buffer is full you allocate another record, chain it with the previous one and keep going until you are out of mem or the process is over.
That should be better performance than realloc function. I believe malloc is trying to give contious block of memory. Therefore the list like structure will be faster and work better.

Resources