This question already has answers here:
Changing address contained by pointer using function
(5 answers)
Closed 1 year ago.
Hey the idea of the code is to scan an array of floats and then create another function that prints that array from the back to the start. For some reason it prints zeros only. Why does it still refer to the part where I set the array to 0? -- float* arr = { 0 };
void ScansFloat(float* arr, int size);
void PrintsFloat(float* arr, int size);
int main()
{
float* arr = { 0 };
ScansFloat(arr, 5);
PrintsFloat(arr, 5);
}
void ScansFloat(float* arr, int size)
{
int save;
arr = (int*)malloc(size * sizeof(int));
for (int i = 0; i < size; i++)
{
printf("Enter number in position %d\n", i+1);
scanf("%f", arr + i);
}
}
void PrintsFloat(float* arr, int size)
{
for (int i = size; i >= 0; i--)
{
printf("Number %d is %f\n", size - i +1, arr + i);
}
}
Pass the address of the pointer.
The below code does not change the calling code's pointer.
void ScansFloat(float* arr, int size) {
...
// Here the prior value of `arr` is lost.
arr = (int*)malloc(size * sizeof(int)); // Wrong type
for (int i = 0; i < size; i++) {
...
scanf("%f", arr + i);
}
}
Instead pass the address of the pointer. Also size to the referenced object, not the type. It avoids coding mistakes.
void ScansFloatAlternate(float** arr, int size) { // **, not *
...
// *arr = (int*)malloc(size * sizeof(int));
*arr = malloc(sizeof **arr * size);
if (*arr == 0) Handle_OutOfMemeory();
for (int i = 0; i < size; i++) {
...
scanf("%f", (*arr) + i);
}
}
float* arr = 0; // or NULL
ScansFloatAlternate(&arr, 5);
Note: other general improvements possible.
Perhaps a different approach: return the allocated pointer. Various improvements applied.
// Return NULL on error
// Use size_t for sizing
float* ScansFloat(size_t n) {
float *arr = malloc(sizeof *arr * n);
if (arr) {
for (size_t i = 0; i < n; i++) {
printf("Enter number in position %zu\n", i + 1);
if (scanf("%f", &arr[i]) != 1) {
// Invalid input, so consume to the end of the line.
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
continue;
}
free(arr);
return NULL;
}
}
}
return arr;
}
Usage
// float* arr = { 0 };
// ScansFloat(arr, 5);
size_t n = 5;
float* arr = ScansFloat(n);
if (arr == NULL) Fail();
...
free(arr); // free when done
Related
I'm having trouble in adding integers to a dynamic array reader, so the second function in the code below. Why do the added numbers in the output look weird? I'm guessing there's a memory problem, I'm somehow allocating new memory incorrectly.
int *create_dyn_array(unsigned int n)
{
int *array = malloc(n * sizeof(*array));
for (size_t i = 0; i < n; i++) {
scanf("%d", &array[i]);
}
return array;
}
int *add_dyn_array(int *arr, unsigned int num, int newval)
{
int *temp = NULL;
temp = realloc(arr, (num + 1)*sizeof(int));
arr = temp;
int *newarray = arr;
while(*arr) {
arr++;
}
int testarray[1];
int *ptr = testarray;
int j = 1;
while (j > 0) {
*ptr = newval;
ptr++;
j--;
}
ptr = testarray;
while(*ptr) {
*arr++ = *ptr++;
}
return newarray;
}
void printarray(const int *array, int size) {
printf("{ ");
for (int i = 0; i < size; ++i) {
printf("%d, ", array[i]);
}
printf(" }\n");
}
int main()
{
int *array = create_dyn_array(5);
printarray(array, 5);
array = add_dyn_array(array, 5, 10);
printarray(array, 6);
array = add_dyn_array(array, 6, 100);
printarray(array, 7);
array = add_dyn_array(array, 7, 1000);
printarray(array, 8);
return 0;
}
What is wrong in the realloc logic?
This is how realloc works:
The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes.
No need to copy anything manually. The whole function can be reduced to this:
int *add_dyn_array(int *arr, unsigned int num, int newval)
{
int *temp = realloc(arr, (num + 1)*sizeof(int));
if(temp == NULL)
{
/* optionally handle errors in some way */
exit(EXIT_FAILURE);
}
temp[num] = newval;
return temp;
}
Please note however that reallocing one single item at a time is very inefficient.
All the solutions I have seen online has calloc() function used twice, is it possible to do with only using it once?
The below code is not printing the correct array elements
int **ptr;
//To allocate the memory
ptr=(int **)calloc(n,sizeof(int)*m);
printf("\nEnter the elments: ");
//To access the memory
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
scanf("%d",ptr[i][j]);
}
}
Since C99 you can use pointers to VLAs (Variable Length Arrays):
int n, m;
scanf("%d %d", &n, &m);
int (*ptr)[m] = malloc(sizeof(int [n][m]));
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
scanf("%d", &ptr[i][j]); // Notice the address of operator (&) for scanf
}
}
free(ptr); // Call free only once
If it's just about minimising the number of calls to memory allocation functions you can created such a jagged array like this:
#include <stdlib.h>
#include <stdio.h>
int ** alloc_jagged_2d_array_of_int(size_t n, size_t m)
{
int ** result = NULL;
size_t t = 0;
t += n * sizeof *result;
t += n*m * sizeof **result;
result = calloc(1, t);
if (NULL != result)
{
for (size_t i = 0; i < n; ++i)
{
result[i] = ((int*) (result + n)) + i*m;
}
}
return result;
}
Use it like this:
#include <stdlib.h>
#include <stdio.h>
int ** alloc_jagged_2d_array_of_int(size_t, size_t);
int main(void)
{
int result = EXIT_SUCCESS;
int ** p = alloc_jagged_2d_array_of_int(2, 3);
if (NULL == p)
{
perror("alloc_jagged_2d_array_of_int() failed");
result = EXIT_FAILURE;
}
else
{
for (size_t i = 0; i < 2; ++i)
{
for (size_t j = 0; j < 3; ++j)
{
p[i][j] = (int) (i*j);
}
}
}
/* Clean up. */
free(p);
return result;
}
I want to append numbers to an empty array and the amount of these numbers is unknown at the start. For example, generating numbers from 1 to 10 and appending one after another.
generateFromOneToTen will save my result in output and count should be 10 after execution. Everything's alright if I print the result in this function.
int generateFromOneToTen(int *output, int count)
{
for (int i = 0; i < 10; i++) {
output = arrayAppendInt(output, i + 1, count);
count++;
}
// Print result of `output` is 1,2,3...10 here
return count;
}
And I implemented arrayAppendInt to dynamic increase the length of an array and append new value after the old ones.
int *arrayAppendInt(int *array, int value, int size)
{
int newSize = size + 1;
int *newArray = (int*) realloc(array, newSize * sizeof(int));
if (newArray == NULL) {
printf("ERROR: unable to realloc memory \n");
return NULL;
}
newArray[size] = value;
return newArray;
}
Here comes the question. When invoking the generation function, numbers will always be NULL. How can I return the generated numbers to the numbers variable?
int *numbers = NULL;
int count = 0;
count = generateFromOneToTen(numbers, 0);
^^^^^^^
You could use a pointer to a pointer of integer (int **):
int generateFromOneToTen(int **output, int count)
{
for (int i = 0; i < 10; i++) {
*output = arrayAppendInt(*output, i + 1, count);
count++;
}
// `*output` is 1,2,3...10 here
return count;
}
You could re-write the arrayAppendInt function like that:
int *arrayAppendInt(int *array, int value, int size)
{
int newSize = size + 1;
int *newArray;
if (array==NULL)
newArray = (int*) malloc ((1+size) * sizeof(int));
else
newArray = (int*) realloc(array, newSize * sizeof(int));
if (newArray == NULL) {
printf("ERROR: unable to realloc memory \n");
return NULL;
}
newArray[size] = value;
return newArray;
}
And call it like that *output = arrayAppendInt(*output, i + 1, i);.
The cleanest solution is (in my opinion) to pack the array+the bookkeeping (size,used) into a structure, and use (a pointer to) this structure as an argument.
#include <stdlib.h>
struct dopedarray {
unsigned size;
unsigned used;
int *array;
};
Now you can put all your allocation and bookkkeeping stuff into a single function (which can be inlined) :
int array_resize(struct dopedarray *ap, unsigned newsize)
{
int *newp;
if(!ap) return -1;
newp = realloc (ap->array, newsize*sizeof*ap->array);
// check return value here...
if (!newp) return -1;
free(ap->array);
ap->array = newp;
ap->size = newsize;
// bookkeeping sanity
if(ap->size > ap->used ) { ap->used > ap->size; }
return 0;
}
The add_element function needs to be changed a bit, too:
int array_add_element(struct dopedarray *ap, int value)
{
if(ap->used >= ap->size){
unsigned newsz;
newsz= ap->used ? 2*ap->used: 4;
array_resize(ap, newsz);
// check return value here...
}
ap->array[ap->used++] = val;
return 0;
}
The complete code to my question:
int generateFromOneToTen(int **output, int count) // +
{
for (int i = 0; i < 10; i++) {
*output = arrayAppendInt(*output, i + 1, count); // ++
count++;
}
return count;
}
int *arrayAppendInt(int *array, int value, int size)
{
int newSize = size + 1;
int *newArray = (int*) realloc(array, newSize * sizeof(int));
if (newArray == NULL) {
printf("ERROR: unable to realloc memory \n");
return NULL;
}
newArray[size] = value;
return newArray;
}
int *numbers = NULL;
int count = 0;
count = generateFromOneToTen(&numbers, 0); // +
This answer also worths reading: https://stackoverflow.com/a/9459803/1951254
I'm new to C and have been trying to tackle this question. It's a continuation of the last thread I made. I made some progress but still have so much to learn and fix.
In short:
In this question a "vector" is a one dimensional array of integers. Therefore an array of vectors would be a two dimensional array that holds one dimensional arrays inside him.
I need to use these variables:
int** vectors- the 2D array
int size -an integer that represents how many vectors exist inside **vectors
int* sizes-a 1D array of integers that represents the length of the vectors
I need to write the following functions:
int init(int ***vectors, int **sizes, int size)
the function allocated memory to **vectors and *sizes with size and initializes vectors to be full of NULLs,and sizes to be full of zeros.
int set(int **vectors, int *sizes, int index, int *tmp, int tmp_size)
the function receives an array of nulls (**vectors)), frees the vector inside **vectors whose index is index and allocates memory for a new vector, whose length is tmp_size and places inside it *tmp's elements.
This is my code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int init(int*** vectors, int** sizes, int size)
{
int i, k,j;
*sizes = (int*)malloc(size * sizeof(int));
if (*sizes == NULL)
return 0;
for (j = 0; j < size; j++)
{
(*sizes)[j] = 0;
}
*vectors = (int**)malloc(size * sizeof(int*));
if (*vectors == NULL)
return 0;
for (i = 0; i < size; i++)
{
(vectors)[i] = NULL;
}
return 1;
}
int set(int **vectors, int *sizes, int index, int *tmp, int tmp_size)
{
if ((vectors)[index] != NULL)
{
free((vectors)[index]);
}
(vectors)[index] = (int*)malloc(tmp_size * sizeof(int));
if ((vectors)[index] == NULL)
return 0;
for (int b = 0; b < tmp_size; b++)
{
(vectors)[index][b] = tmp[b];
}
sizes[index] = tmp_size;
return 1;
}
int main()
{
int size, i, length, indexhere;
int** vectors = NULL;
int* sizes = NULL;
int* tmp = NULL;
int* p = &vectors;
int tempindex;
printf("\nPlease enter an amount of vectors:\n");
scanf("%d", &size);
init(p, &sizes, size);
printf("Enter index\n");
scanf("%d", &indexhere);
printf("Enter Length\n");
scanf("%d", &length);
tmp = (int*)malloc(length * sizeof(int));
printf("Enter elements:\n");
for (int g = 0; g < length; g++)
scanf("%d", &tmp[g]);
set(&vectors, sizes, indexhere, tmp, length);
system("pause");
return 0;
}
Could someone explain please why the program always crashes?
In init function (vectors)[i] = NULL; should actually be (*vectors)[i] = NULL;
When calling set function from main you should pass vectors instead of &vectors.
There also seems to be several pointer type mismatches in your code, so you should really pay attention to compiler's warnings. This is because C unfortunately allows implicit conversions between incompatible pointers, unlike C++ for example.
You call set like this
set(&vectors, sizes, indexhere, tmp, length);
but the first argument is declared as an int **. By passing &vector you're passing a pointer to vector, i.e. something of type int ***. This mismatch will lead to undefined behavior and probable crashes.
Here is a complete working example.
#include <stdio.h>
#include <stdlib.h>
void destroyVectors(int **vectors, int size)
{
for (int i = 0; i < size; i++)
{
free(vectors[i]);
}
}
int init(int*** vectors, int** sizes, int size)
{
int i, j;
*sizes = (int*)malloc(size * sizeof(int));
if (*sizes == NULL)
return 0;
for (j = 0; j < size; j++)
{
(*sizes)[j] = 0;
}
*vectors = (int**)malloc(size * sizeof(int*));
if (*vectors == NULL)
return 0;
for (i = 0; i < size; i++)
{
(*vectors)[i] = NULL;
}
return 1;
}
int set(int **vectors, int *sizes, int index, int *tmp, int tmp_size)
{
if ((vectors)[index] != NULL)
{
free((vectors)[index]);
}
(vectors)[index] = (int*)malloc(tmp_size * sizeof(int));
if ((vectors)[index] == NULL)
return 0;
for (int b = 0; b < tmp_size; b++)
{
(vectors)[index][b] = tmp[b];
}
sizes[index] = tmp_size;
return 1;
}
int main()
{
int size = 0, length = 0, indexhere = 0;
int** vectors = NULL;
int* sizes = NULL;
int* tmp = NULL;
printf("\nPlease enter an amount of vectors:\n");
scanf("%d", &size);
init(&vectors, &sizes, size);
printf("Enter index\n");
scanf("%d", &indexhere);
printf("Enter Length\n");
scanf("%d", &length);
tmp = (int*)malloc(length * sizeof(int));
printf("Enter elements:\n");
for (int g = 0; g < length; g++)
scanf("%d", &tmp[g]);
set(vectors, sizes, indexhere, tmp, length);
for(int i = 0; i < length; ++i)
printf("byte: %d\n", vectors[indexhere][i]);
printf("sizes index: %d\n", sizes[indexhere]);
free(tmp);
free(sizes);
destroyVectors(vectors, size);
return 0;
}
The exercise, that I have to complete says:
That array_remove function must remove from the array arr the value, that is in the position pos, and scale of a position successive values of pos, and eventually change the array size for no gaps.
If this value is not included in the array (if pos is greater than pn (array size)), then you should not do anything.
My problem is:
Probably very wrong to use the malloc function, because when it is performed, it shows the following error:
MAIN.C:
#include "array.h"
int main(void)
{
double arr[] = { 1.0,2.0,3.0,4.0,5.0 };
size_t pn = 5;/*array length*/
size_t pos = 2;/*position of the number to be deleted*/
array_remove(arr, &pn, pos);
}
ARRAY.C:
#include "array.h"
void array_remove(double *arr, size_t *pn, size_t pos)
{
int x = *pn;
int y = pos;
if (x > y)
{
for (int i = y; i < x; i++)
{
arr[i] = arr[i + 1];
}
realloc(&arr, sizeof(double) * 4);
}
}
According to the C docs:
realloc Reallocates the given area of memory that must be previously allocated
by malloc(), calloc() or realloc() and not yet freed with free,
otherwise, the results are undefined.
You have an out of bound problem as well at the following lines when i=x-1 you try to access at arr[i+1] = arr[x=pn]:
for (int i = y; i < ; i++) {
arr[i] = arr[i + 1];
Check the following code out *(live: https://ideone.com/mbSzjL
#include<stdlib.h>
void array_remove(double **arr, int *pn, int pos) {
int x = *pn;
int y = pos;
if (x > y) {
//check if after deletion size is zero!
if (x > y) {
for (int i = y; i < x-1; i++) {
(*arr)[i] = (*arr)[i + 1];
}
*arr=realloc(*arr, sizeof(double) * x-1);
*pn=*pn-1;
}
}
}
int main(void) {
int pn = 20;/*array length*/
int pos = 5;/*position of the number to be deleted*/
double *arr = malloc(sizeof(double)*pn);
printf("%p\n",arr);
for(int i=0;i<pn;i++){
arr[i] = i;
}
for(int i=0;i<pn;i++){
printf("%.f ",arr[i]);
}
printf("\n");
printf("%i\n",pn);
array_remove(&arr, &pn, pos);
printf("%p\n",arr);
for(int i=0;i<pn;i++){
printf("%.f ",arr[i]);
}
printf("\n");
printf("%i",pn);
free(arr);
}
Don't forget to realloc using the right size (not using an hardcoded 4) and check for the edge case in which size is zero after deletion!
In addition,
free the memory at the end and to update the size variable.
http://en.cppreference.com/w/c/memory/realloc
arr array is stack allocated. You cannot realloc something that wasn't mallocated.
You probably want something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
bool array_remove(double **arr, size_t *pn, size_t pos)
{
int x = *pn - 1;
int y = pos;
int i;
double *temp;
if (x > y) {
for (i = y; i < x; i++) {
(*arr)[i] = (*arr)[i + 1];
}
temp = realloc(*arr, sizeof(double) * x);
}
if (arr != NULL)
{
*arr = temp;
*pn -=1;
return true;
}
else
{
return false;
}
}
int main(void)
{
size_t pn = 5; // array length
size_t pos = 2; // position of the number to be deleted
int i;
double *arr = malloc(pn*sizeof(double));
if (arr != NULL)
{
for (i=0; i<pn; i++)
{
arr[i] = (double)(i+1);
}
if (array_remove(&arr, &pn, pos) == false)
{
printf("Failed to remove element %zu\n", pos);
}
for (i=0; i<pn; i++)
printf ("arr[%d]: %f\n", i, arr[i]);
free(arr);
}
else
{
printf("Failed to alloc array\n");
}
return 0;
}
As you can see I changed the loop of array_remove. In your code you are addressing the array out of bound on the last loop, because of i=4 and then:
arr[i] = arr[i + 1]; is arr[4] = arr[5]
Indexes of a 5 elements array start from 0 to 4.
actually you have a different problem here:
int x = *pn; //x=5
int y = pos; //y=2
if (x > y) {
for (int i = y; i < x; i++) {
arr[i] = arr[i + 1];
}
On the last iteration, you do
arr[4] = arr[5]
This is out of range addressig and that's probably your problem, or at least your first one.
Also, even though it's not technically wrong it's conceptually wrong:
array_remove(arr, &pn, pos);
Never pass a value by pointer unless you plan on modifying it. Not the case here, so you can pass it by value.