Related
I am getting a segmentation fault from the below program.
#include <stdio.h>
#include <string.h>
void removeProcess(int*, int);
void removeProcessN(char**, int, int);
void main() {
int numPro = 0, quanTime = 0, contTime = 0, i, elemNum, time = 0;
//Supply variables with user input
printf("Enter number of processes: ");
scanf("%d", &numPro);
printf("Enter context switch time: ");
scanf("%d", &contTime);
printf("Enter quantum of time: ");
scanf("%d", &quanTime);
//Create array of number of process time
int proTime[numPro];
//Create string array for better output
char *proNames[numPro];
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
sprintf(proNames[i], "p%d", i);
}
elemNum = 0;
//While a process remains active
while (numPro != 0) {
//Retrieves the element being worked with
elemNum = elemNum % numPro;
//Describe process working with
printf("Executing process %s\nStart time = %d\n", proNames[elemNum], time);
proTime[elemNum] -= quanTime;
//If process time complete, remove process
if (proTime[elemNum] <= 0){
removeProcess(proTime, elemNum);
removeProcessN(proNames, elemNum, numPro);
--numPro;
}
//Add amount of time with context time
time = time + quanTime + contTime;
elemNum++;
}
}
/**
*#param *array pointer to an array of integers
*#param elem int of the element to remove
* Removes an element 'elem' from the supplied integer array.
*/
void removeProcessN(char **array, int numElem, int elem) {
char *temparray[numElem - 1];
//Copy array to temparray except for elem to remove
int i;
for (i = 0; i < elem; i++) {
if (i == numElem) {
continue;
} else {
temparray[i] = array[i];
}
}
//End by setting the pointer of array to the temparray
array = temparray;
}
/**
*#param *array pointer to an array of integers
*#param elem int of the element to remove
* Removes an element 'elem' from the supplied integer array.
*/
void removeProcess(int *array, int elem) {
//Number of elements in the array
int numElem = sizeof(array) / sizeof(int);
int temparray[numElem - 1];
//Copy array to temparray except for elem to remove
int i;
for (i = 0; i < numElem; i++) {
if (i == elem) {
continue;
} else {
temparray[i] = array[i];
}
}
//End by setting the pointer of array to the temparray
array = temparray;
}
I know the segmentation fault is coming from sprintf. I am trying to simulate how an operating system would complete a process using round robin. I have tried using sprintf because that's what tutorials were saying online to use when trying to manipulate strings. The removeProcessN is just removing an index from the array proNames. I am mostly just concerned with the sprintf.
I have tried malloc when I do the sprintf but it would not even compile at that point. If someone could offer an explanation I'd be appreciative.
The problem here is that proNames is an array of pointers, but they are
uninitialized, so passing it to sprintf to write something, will crash. You
would have either use a double array or allocate memory with malloc. But as
you are only printing integers and the string representatuion of integers has a
maximal length, allocating memory with malloc will be more harder, because you
have to check that malloc doesn't return NULL, you have to free the memory
later, etc.
So I'd do:
char proNames[numPro][30]; // 28 characters for an int (usually 4 bytes long)
// should be more than enough
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
sprintf(proNames[i], "p%d", i);
}
Your removeProcessN would need to change as well:
void removeProcessN(int numElem, int elem, int dim, char (*array)[dim]) {
for(int i = elem; i < numElem - 1; ++i)
strcpy(array[i], array[i+1]);
array[numElem - 1][0] = 0; // setting last element to empty string
}
Note that I moved the array argument at the last position, otherwise numElem
is not known and the compiler would return an error.
And now you can call it like this:
removeProcessN(elemNum, numPro, 30, proNames);
The 30 comes from the char proNames[numProp][30]; declaration.
I'd like to comment on the last line of your function removeProcessN:
//End by setting the pointer of array to the temparray
array = temparray;
That is not correct, first because temparray is local variable and ceases to
exist when the function returns. And array is local variable in the function,
so changing it doesn't affect anybody.
The alternative with memory allocation would look like this:
char *proNames[numPro];
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
int len = snprintf(NULL, 0, "p%d", i);
proNames[i] = malloc(len + 1);
if(proNames[i] == NULL)
{
// error handling, free the previously allocated
// memory, and return/exit
}
sprintf(proNames[i], "p%d", i);
}
and removeProcessN:
void removeProcessN(char **array, int numElem, int elem) {
char *to_remove = array[elem];
for(int i = elem; i < numElem - 1; ++i)
array[i] = array[i+1];
free(to_remove);
array[numElem - 1] = NULL; // setting last element to NULL
// makes freeing easier as
// free(NULL) is allowed
}
And the way you originally called the removeProcessN would be OK.
If you eventually call removeProcessN for all processes, then all the memory
should be freed because removeProcessN frees it. If there are some elements
that remain in the array, then you have to free them later.
OP posted in the comments
My theory was that temparray would be a pointer to an array so I could just remove an index from the main array.
So when I say array = temparray, the pointer for array points to temparray. I know it worked for removeProcess. Is it different for strings?
The array = temparray also has no effect in removeProcess, array is still
a local variable and changing where it points to has no effect at all, because
you are changing a local variable only.
Besides the code is wrong:
int numElem = sizeof(array) / sizeof(int);
this only works for pure arrays, it does not work for pointers because
sizeof(array) returns you the size that a pointer of int needs to be stored.
Like the other function, you need to pass the site the array to the function.
If you say that this function worked, then just only by accident, because it
yields undefined behavior. By incorrectly calculating the number of elements,
temparray will have the wrong size, so here temparray[i] = array[i]; you may
access beyond the bounds which leads to undefined behaviour. Undefined behaviour
means that you cannot predict what is going to happen, it could be anything from
crashing to formatting your hard drive. Results that result from undefined
behaviour are useless.
And again array = temparray; just changes where the local variable array is
pointing, the caller of removeProcess doesn't see that.
The correct version would be:
int removeProcess(int *array, int elem, int numElem) {
if(array == NULL)
return 0;
// nothing to do if the elemnt to be removed is
// the last one
if(elem == numElem - 1)
return 1;
// overwriting the memory, because memory
// regions overlap, we use memmove
memmove(array + elem, array + elem + 1, numElem - elem - 1);
return 0;
}
So, to make it clear:
Let's look at this code:
void sum(int *array, size_t len);
{
int c[len];
array = c;
}
void bar(void)
{
int x[] = { 1, 3, 5 };
size_t len = sizeof x / sizeof *x;
sum(x, sizeof x / sizeof *x);
printf("x[0] = %d, x[1] = %d, x[2] = %d\n", x[0], x[1], x[2]);
}
sum has only a copy of the pointer you've passed in bar, so from bar's
point of view, sum changed the copy, so bar will print
x[0] = 1, x[1] = 3, x[2] = 5.
But if you want that the caller sees any change, then you to access through the
pointer:
void sum(int *array, size_t len)
{
int c[len];
for(size_t i = 0; i < len; ++i)
array[i] += 10;
array = c;
}
With this version bar would print x[0] = 11, x[1] = 13, x[2] = 15 and
and array = c will have no effect on bar.
I have to read from a file which has a unknown number of students records in it written in binary, then sort the students by their GPA and send to stdout.
Our sort function had to be like
void insertion_sort(Student **, int);
That's why I choose to use an pointer to a pointer to Student (probably not the best solution? I think I could have just sent an pointer to Student like this (&p_to_Student, n) ?)
The code is bellow, the problem is that when I print the first element of what p is pointing to (the first students name) I get gibberish, the other students are fine.
I checked the value of p, and it does change after realloc() is called, and because it's also the address of the first element of p (right?).
Also checked with Valgrind and it returns a bunch of errors about memory leaks!
The code runs fine when there is no realloc() call, also when I initialize p after I'm done reading the file. So it must be something to do with not using realloc() correctly.
Bonus question: is this a proper way to read an unknown number of data entries from a file?
#include <stdio.h>
#include <stdlib.h>
struct student {
char name[30];
char surname[30];
double GPA;
};
typedef struct student Student;
void insertion_sort(Student **arr, int n)
{
int i,j;
for (i=1; i<n; i++)
{
Student *tmp = arr[i];
for (j=i; j>0 && (tmp->GPA > arr[j-1]->GPA); j--)
arr[j] = arr[j-1];
arr[j] = tmp;
}
}
int main(int argc, char **argv)
{
FILE *in;
Student s, *arr, **p;
size_t ret;
int i = 1, n=0, c=2;
in = fopen(argv[1], "rb");
if (in == NULL)
return printf("Can't open file!\n"), 1;
arr = (Student*) malloc(c*sizeof(Student*));
p = (Student**) malloc(c*sizeof(Student*));
do
{
ret = fread(&s, sizeof(Student), 1, in);
if (ret)
{
if (n == c)
{
arr = (Student*) realloc(arr, (c*=2)*sizeof(Student));
p = (Student**) realloc(p, c*sizeof(Student*));
}
// when I print the value of pointer p
// the values is changed when realloc() is called
printf("p = %p\n", p);
arr[n] = s;
p[n] = arr+n;
n++;
}
} while (ret);
fclose(in);
// If I do this instead the program runs correctly
//p = (Student**) malloc(c*sizeof(Student));
//for (int i=0; i<n; i++)
//{
//p[i] = arr+i;
//}
insertion_sort(p, n);
for (i=0; i<n; i++)
{
printf("%2d. %-20s %-20s %7.2lf\n", i+1, p[i]->name,
p[i]->surname, p[i]->GPA);
}
free(arr);
free(p);
return 0;
}
realloc may change the pointer. That means all pointers into that pointer may become invalid. In your case, p holds pointers into arr.
Your problem is not that the value of p changes, but that the old values of p are no longer valid when the value of arr changes.
To illustrate (all pointer and size values are made up):
sizeof(stud) == 16;
allocate arr: arr == 0x00100000;
1st value: arr[0] = stud1; p[0] = &arr[0]; // 0x00100000
2nd value: arr[1] = stud2; p[1] = &arr[1]; // 0x00100010
reallocate arr: arr == 0x00200000;
old address of arr is no longer valid!
3rd value: arr[0] = stud1; p[2] = &arr[2]; // 0x00200020
Now your pointer array looks like this:
p[0] == 0x00100000 // no longer valid!
p[0] == 0x00100010 // no longer valid!
p[0] == 0x00200020 // okay
Because you need p only for your sorting, the approach you have commented out – to allocate p at one go before sorting – is better.
realloc is useful only if you don't now beforehand how big your array is, so you should use it as long as you are building the array. When you are done building the array and you can be sure that arr will stay the same you should create the array of pointers, p.
I am writing a C program that involves passing 2D arrays between functions changing their size and entries. I decided to use dynamic arrays with pointers for this.
Whenever I free the pointers to an array, I find that I wipe the values held in other arrays. I can successfully change which array a pointer points to. I believe this is an issue with the way I'm freeing my pointers or declaring them. Below is code I'm using to create and free pointers to my arrays.
int** create_array(int m, int n)
{
int i;
int* values = calloc(m * n, sizeof(int));
int** rows = malloc(n * sizeof(int*));
for(i = 0; i < n; i++) {
rows[i] = values + (i * m);
}
return rows;
}
void destroy_array(int** arr)
{
free(arr[0]);
free(arr);
}
OLD CODE to Create and Free Pointers
int** create_array(int m, int n)
{
int i;
int* values = calloc(m * n, sizeof(int));
int** rows = malloc(n * sizeof(int*));
for(i = 0; i < n; i++) {
rows[i] = values + (i * m * sizeof(int));
}
return rows;
}
void destroy_array(int** arr, int m, int n)
{
int i;
for(i = 0; i < n; i++) {
free(arr[i]);
}
free(arr);
}
My program gets a segfault after I destroy the pointers to an array and try to read values from another array. Below is the code where I destroy my pointers to these arrays. positions_last and positions are both arrays that I can read from properly before this point.
positions_last = positions;
printf("- %d %d %d - ", positions_last[0][1], positions_last[1][1], positions_last[2][1]);
fflush(stdout); // this prints fine
destroy_array(positions);
printf("- %d %d %d - ", positions_last[0][1], positions_last[1][1], positions_last[2][1]);
fflush(stdout); // this does not print, I get a segfault at this point
I just did an elementary test which suggests that the issue lies in my current code for creating or destroying arrays (so far as I know).
int** positions2 = create_array(10, 3);
int** positions3 = create_array(10, 3);
printf("%d %d %d", positions3[0][1], positions3[1][1], positions3[2][1]);
fflush(stdout); // This line prints fine
positions3 = positions2;
destroy_array(positions2);
printf("%d %d %d", positions3[0][1], positions3[1][1], positions3[2][1]);
fflush(stdout); // This line triggers a segfault
Anyone have an idea what the issue may be?
You called calloc once and malloc once, but then you're calling free n+1 times (and of course you're freeing the same value, arr[1] n times). There should be exactly one free for each malloc or calloc.
void destroy_array(int** arr)
{
free(arr[0]);
free(arr);
}
This line
rows[i] = values + (i * m * sizeof(int));
should be
rows[i] = values + (i * m);
The reason behind this is that values is a typed pointer, namely pointing to int. Adding 1 to it increases it by 1 * sizeof (int). Your code assumes it would be increased by 1 only.
This are basic pointer arithmetics: http://cslibrary.stanford.edu/104/ ;-)
So you are running into undefined behaviuor even before the 1st call to free().
Also malloc/calloc and free follow the pattern:
One Allocation --> One Freeing
So freeing might look like this:
free(*arr); /* Free what had been allocated to "values". */
free(arr); /* Free what had been allocated to "rows". */
The code you show does differently, as pointed out by zindorsky's answer.
Regarding your edit:
This
positions_last = positions;
does not copy the array, its elements, but just the reference to the array 1st member. SO if you deallocate positions also positions_last points to freed, that is then invalif memory. Accessing it provokes UB, as this lines does:
printf("- %d %d %d - ", positions_last[0][1], positions_last[1][1], positions_last[2][1]);
Lesson learned: In C one cannot copy an array by a simple assignment
How to allocate dynamic memory for 2d array in function ?
I tried this way:
int main()
{
int m=4,n=3;
int** arr;
allocate_mem(&arr,n,m);
}
void allocate_mem(int*** arr,int n, int m)
{
*arr=(int**)malloc(n*sizeof(int*));
for(int i=0;i<n;i++)
*arr[i]=(int*)malloc(m*sizeof(int));
}
But it doesn't work.
Your code is wrong at *arr[i]=(int*)malloc(m*sizeof(int)); because the precedence of the [] operator is higher than the * deference operator: In the expression *arr[i], first arr[i] is evaluated then * is applied. What you need is the reverse (dereference arr, then apply []).
Use parentheses like this: (*arr)[i] to override operator precedence. Now, your code should look like this:
void allocate_mem(int*** arr, int n, int m)
{
*arr = (int**)malloc(n*sizeof(int*));
for(int i=0; i<n; i++)
(*arr)[i] = (int*)malloc(m*sizeof(int));
}
To understand further what happens in the above code, read this answer.
It is important that you always deallocate dynamically allocated memory explicitly once you are done working with it. To free the memory allocated by the above function, you should do this:
void deallocate_mem(int*** arr, int n){
for (int i = 0; i < n; i++)
free((*arr)[i]);
free(*arr);
}
Additionally, a better way to create a 2D array is to allocate contiguous memory with a single malloc() function call as below:
int* allocate_mem(int*** arr, int n, int m)
{
*arr = (int**)malloc(n * sizeof(int*));
int *arr_data = malloc( n * m * sizeof(int));
for(int i=0; i<n; i++)
(*arr)[i] = arr_data + i * m ;
return arr_data; //free point
}
To deallocate this memory:
void deallocate_mem(int*** arr, int* arr_data){
free(arr_data);
free(*arr);
}
Notice that in the second technique malloc is called only two times, and so in the deallocation code free is called only two times instead of calling it in a loop. So this technique should be better.
Consider this: Just single allocation
int** allocate2D(int m, int n)
{
int **a = (int **)malloc(m * sizeof(int *) + (m * n * sizeof(int)));
int *mem = (int *)(a + m);
for(int i = 0; i < m; i++)
{
a[i] = mem + (i * n);
}
return a;
}
To Free:
free(a);
If your array does not need to be resized (well, you can, but il will be a bit more complicated), there is an easier/more efficient way to build 2D arrays in C.
Take a look at http://c-faq.com/aryptr/dynmuldimary.html.
The second method (for the array called array2) is quite simple, less painful (try to add the tests for mallocs' return value), and way more efficient.
I've just benchmarked it, for a 200x100 array, allocated and deallocated 100000 times:
Method 1 : 1.8s
Method 2 : 47ms
And the data in the array will be more contiguous, which may speed things up (you may get some more efficient techniques to copy, reset... an array allocated this way).
Rather allocating the memory in many different block, one can allocate this in a consecutive block of memory.
Do the following:
int** my2DAllocation(int rows,int columns)
{
int i;
int header= rows *sizeof(int *);
int data=rows*cols*sizeof(int);
int ** rowptr=(int **)malloc(header+data);
if(rowptr==NULL)
{
return NULL:
}
int * buf=(int*)(rowptr+rows);
for(i=0;i<rows;i++)
{
rowptr[i]=buf+i*cols;
}
return rowptr;
}
That is an unnecessarily complicated way of allocating space for an array. Consider this idiom:
int main(void) {
size_t m = 4, n = 3;
int (*array)[m];
array = malloc(n * sizeof *array);
free(array);
}
I have tried the following code for allocating memory to 2 dimensional array.
#include<stdio.h>
#include<malloc.h>
void main(void)
{
int **p;//double pointer holding a 2d array
int i,j;
for(i=0;i<3;i++)
{
p=(int**)(malloc(sizeof(int*)));//memory allocation for double pointer
for(j=(3*i+1);j<(3*i+4);j++)
{
*p = (int*)(malloc(sizeof(int)));//memory allocation for pointer holding integer array
**p = j;
printf(" %d",**p);//print integers in a row
printf("\n");
p++;
}
}
}
Output of the above code is:-
1 2 3
4 5 6
7 8 9
In order to understand 2 dimensional array in terms of pointers, we need to understand how it will be allocated in memory, it should be something like this:-
1 2 3
1000 --> 100 104 108
4 5 6
1004 --> 200 204 208
7 8 9
1008 --> 300 304 308
from the above, we understand that, when we allocate memory to pointer p which is a double pointer, it is pointing to an array of integers, so in this example, we see that the 0x1000 is pointer p.
This pointer is pointing to integer pointer *p which is array of integers, when memory is allocated inside the inner for loop, during first iteration the pointer is 0x100 which is pointing to integer value 1, when we assign **p = j. Similarly it will be pointing to 2 and 3 in the next iterations in the loop.
Before the next iteration of the outer loop, double pointer is incremented, inside the next iteration, as is seen in this example the pointer is now at 0x1004 and is pointing to integer pointer which is an array of integers 4,5,6 and similarly for the next iterations in the loop.
Try the following code:
void allocate_mem(int*** arr,int n, int m)
{
*arr=(int**)malloc(n*sizeof(int*));
for(int i=0;i<n;i++)
*(arr+i)=(int*)malloc(m*sizeof(int));
}
2d Array dynamically array using malloc:
int row = 4;
int column = 4;
int val = 2;
// memory allocation using malloc
int **arrM = (int**)malloc (row*sizeof(int*));
for (int i=0;i<row;i++)
{
arrM[i] = (int*)malloc(column*sizeof(int));
// insert the value for each field
for (int j =0;j<column;j++,val++)
{
arrM[i][j] = val;
}
}
// De-allocation
for (int i=0;i<row;i++)
{
free(arrM[i]);
}
free(arrM);
arrM = 0;
//
// Now using New operator:
//
int **arr = new int*[row];
int k = 1;
for (int i=0;i<row;i++)
{
arr[i] = new int[column];
// insert the value for each field
for (int j =0;j<column;j++,k++)
{
arr[i][j] = k;
}
}
cout<<"array value is = "<<*(*(arr+0)+0)<<endl;
cout<<"array value is = "<<*(*(arr+3)+2)<<endl;
// Need to deallcate memory;
for (int i=0;i<row;i++)
{
delete [] arr[i];
}
delete []arr;
arr = 0;
I was writing a program to concatenate two arrays in C. I am allocating memory for a third array and using memcpy to copy the bytes from the two arrays to the third. The test output is:
1 2 3 4 5 0 0 0 0 0
Is there anything wrong with this approach?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int *array_concat(const void *a, int an,
const void *b, int bn)
{
int *p = malloc(sizeof(int) * (an + bn));
memcpy(p, a, an*sizeof(int));
memcpy(p + an*sizeof(int), b, bn*sizeof(int));
return p;
}
// testing
const int a[] = { 1, 2, 3, 4, 5 };
const int b[] = { 6, 7, 8, 9, 0 };
int main(void)
{
unsigned int i;
int *c = array_concat(a, 5, b, 5);
for(i = 0; i < 10; i++)
printf("%d\n", c[i]);
free(c);
return 0;
}
memcpy(p + an*sizeof(int),...
this second memcpy, you are trying to add 5 * sizeof(int) to an int pointer, p. However, when you add to a pointer, it already knows that it has to deal with sizeof(type), so you don't have to tell it.
memcpy(p + an,...
Remove the multiplication *sizeof(int) from the 1st argument of memcpy. Keep it in the argument of malloc and the 3rd argument of memcpy.
This is because p + an points to an int which is an ints to the right from p -- that is, the int which is an*sizeof(int) bytes to the right from p.
p is a pointer to int. When you add an integer to a pointer to an int, the compiler multiplies the integer by the size of an integer. The net result is to multiply by the size of an integer twice: what you're getting is "p + an*sizeof(int)" is p + (number of elements in a) * (number of bytes in an int) * (number of bytes in an int).
memcpy(p + an*sizeof(int), b, bn*sizeof(int));
should be:
memcpy(p + an, b, bn*sizeof(int));
You should remove sizeof(int) from second memcpy where you use pointer arithmetic (+).
Compiler doing this by itself depending on type of pointer.
you should see the definition of the memcpy, which copy's n "bytes" from the src to the dst area. so,you just need to times sizeof(int) only for the 3rd argument. and for "c", it's a pointer of int type, so, it does know that "+an" means move p forward to the an+1 int position.
Merging can be done by sorting the elements of the elements which are going to be merged code for merging two arrays
#include<stdio.h>
void sort(int arr[],int size){ // sorting function
int i,j,temp;
for(i=0;i<size;i++){
for(j=i;j<size;j++){
if(arr[i]>arr[j]){
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
int main(){
int a[10],b[10],c[10];
int n,i,k=0,j=0;
printf("Enter the size of the array:");
scanf("%d",&n);
for(i=0;i<n;i++){
printf("Enter the element of array A at index %d:",i); //input array A
scanf("%d",&a[i]);
}
sort(a,n);
for(i=0;i<n;i++){
printf("Enter the element of array B at index %d:",i); //Input array B
scanf("%d",&b[i]);
}
sort(b,n);
for(i=0;i<(n+n);i++){ // merging the two arrays
if(a[k]<b[j]){
c[i] = a[k];
k++;
}
else{
c[i] = b[j];
j++;
}
}
printf("Merged Array :\n");
for(i=0;i<(n+n);i++){
printf("c -> %d ",c[i]);
}
return 0;
}
Reference C program to Merge Two Arrays after Sorting