Use of sizeof() with normal arrays and garrays - c

it is a practice program to sort GArrays, I have used sizeof() to know the size of my arrays.
Thinking logically, sizeof(x) should be 24 i.e 6 integers * size of each integer i.e 4 - 6*4.
But when I put these integers into my GArray, the size is 8.
why is it 8, why not 32? .. as g_array_new allocates bytes in powers of 2? and nearest power of 2 near 24 is 2^5 i.e 32
/*************************************************************************************************************
* FILE NAME : ex-garray-6.c
*
* DESCRIPTION : sort Garray using GCompareFunc (Not used in GIMP, Gaim or Evolution)
*
************************************************************************************************************/
#include<glib.h>
#include<stdio.h>
/*************************************************************************************************************
* FUNCTION NAME : print_arr
*
* DESCRIPTION : prints entire array using len and g_array_index
*
* RETURNS : void
*
************************************************************************************************************/
void print_arr(GArray* arr)
{
int i = 0;
printf("\n Array : \n");
for (i = 0; i < (arr->len); i++)
{
printf("%d\n", g_array_index(arr, int, i));
}
}
/*************************************************************************************************************
* FUNCTION NAME : compare_ints
*
* DESCRIPTION : utilized qsort() to sort elements of the unsorted array.
* arguments are two gpointers.They are typecasted to int pointers
* int the function
*
* RETURNS : int - -ve if first arg is smaller than second arg
* 0 if first arg is equal to second arg
* +ve - second arg is smaller than first arg
*
************************************************************************************************************/
int compare_ints( gpointer* a, gpointer* b)
{
int* x = (int*)a;
int* y = (int*)b;
return (*x - *y);
}
/*************************************************************************************************************
* FUNCTION NAME : main.c
*
* DESCRIPTION : main.c declares GArray,allocates memory to it, appends 6 integers into the array,* uses g_array_sort to print the array, uses print_arr function to print the array * frees array at end.
*
* RETURNS : SUCCESS
*
************************************************************************************************************/
int main(int argc, char** argv)
{
// 1. declare GArray pointer variable and allocate memory to it
GArray* arr = g_array_new(FALSE, FALSE, sizeof(int));
// g_array_set_size(arr,8); - didn't work to fix size to 8 bytes
// 2. initialize int array of 6 elements say x
int x[6] = {500,400, 500, 700, 200, 300};
// 3. append in the array
arr = g_array_insert_vals(arr,0, x, 6);
printf("\n size of x : %d \n size of arr : %d", sizeof(x), sizeof(arr));
// 4. print the array
print_arr(arr);
/* 5. sort the array using
g_array_sort(
<GArray pointer variable>,
(GCompareFunc)<name of the compare function>);
- compare function uses qsort()-
-returns -ve a<b
-returns 0 a = b
-returns +ve b = a
*/
/* 5.5 alternate sorting function -
g_array_sort_with_data(
<same as g_array_sort>,
<same as g_array_sort>,
<gpointer to user-data>); */
printf("\n Array after sorting \n ");
g_array_sort(arr, (GCompareFunc)compare_ints);
// 6. print garray
print_arr(arr);
// 7. free garray
g_array_free(arr, TRUE);
}

Yes I got the answer:
GArray is a structure
having 2 elements 1 of gchar type and other of gunit type
gchar is of 1 byte
gunit is of 4 bytes
so sizeof(GArray) or sizeof(arr) here would be 1+4 = 5 then extending it to nearest power of 2 i.e 2^3 is 8 :)

As said in commentaries, arr is not an array, it is a pointer to a GArray (which is not an array neither, cf GArray reference).
x is an array, so it size is size of an item * number of items, so 6 * sizeof(int).
arr is a pointer, and pointer size depend to the compiler and system used, in your case, a int * has a size of 8.

Related

How to properly sum the elements of an array w/out getting large random outputs

I wrote two functions and call the functions in main.
Function 1 – I wrote a function that returns void and takes an int * (pointer to integer array) or int[], and int (for the size). The function needs to initialize all the elements of the array to non-zero values.
Function 2 – I wrote another function that returns int and takes an const int * (pointer to integer array) or int[], and int (for the size). The function should sum all the elements of the array and return the sum.
In main I defined an integer array of size 5. Called function 1 in main to initialize the values of the array. Called function 2 in main to get the sum and print the value of the sum to the console.
My problem is the program runs but the print out for sum we are getting is a large (in the millions), random, number and is not the expected answer of 15. Anyone who can help us get the correct answer would be greatly appreciated
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#pragma warning(disable: 4996)
void func1(int* ptr, int size);
int func2(const int* ptr, int size);
int main()
{
int grid[5];
func1(grid, 5);
func2(grid, 5);
}
void func1(int* ptr, int size)
{
*ptr = 1, 2, 3, 4, 5;
}
int func2(const int* ptr, int size)
{
int sum;
sum = ptr[0] + ptr[1] + ptr[2] + ptr[3] + ptr[4]; // *(ptr + 0); putting an asterisk makes it so that it changes the entire "ptr" value and the "[0]" value
printf("\n\nThe sum of the integers in the array is %d.\n\n", &sum);
}
*ptr = 1, 2, 3, 4, 5;
does not do what you think it does. It actually evaluates all the integer constants but sets ptr[0] to be 1 (see comma operator for more detail), leaving all the others at some arbitrary value.
Note that it is not evaluating *ptr = (1, 2, 3, 4, 5) (which would set *ptr to 5) but is actually evaluating (*ptr = 1), 2, 3, 4, 5 - this works because something like 42 is actually a valid C statement, albeit not very useful.
If you're trying to set the array to increasing values, just use something like:
for (int i = 0; i < size; i++)
ptr[i] = i + 1;
You probably also want to do that when summing the values since it should depend on the passed-in size rather than just summing five values:
int sum = 0;
for (int i = 0; i < size; i++)
sum += ptr[i];
Additionally, the value you are printing out is not the sum, it's the address of the variable containing the sum (a decent compiler will warn you about this). You should be using sum in your printf rather than &sum.
And, as a final note, the signature for func2 indicates that you should actually be returning the sum rather than just printing it. So I would suggest removing the printf from that function and simply doing:
return sum;
Then you can put the printf into the caller (main) as follows:
int main(void)
{
int grid[5];
func1(grid, sizeof(grid) / sizeof(*grid));
int sum = func2(grid, sizeof(grid) / sizeof(*grid));
printf("The sum of the integers in the array is %d.\n\n", sum);
return 0;
}
Note the use of sizeof(grid) / sizeof(*grid), which is basically the number of array elements in grid - this will allow you to resize grid by simply changing it in one place to something like int grid[42] and still have all the code work with the updated size.
Not actually necessary for your code but it's best to get into good programming habits early (more descriptive names for your functions may also be a good idea).
Line *ptr = 1, 2, 3, 4, 5; assigns ptr[0] value and leaves other spots unitilized so when you sum it, it will be random memory.
You should use for like this to initialize
for(int i=0;i<size;i++)
{
ptr[i] = i+1;
}
and similiar aproach to sum it.

Array becomes larger than declared [duplicate]

This question already has answers here:
How do I determine the size of my array in C?
(24 answers)
Closed 5 years ago.
I'm writing a function that is supposed to split a string on "-" and return and array containing the parts from the string, so if the string is:
2017-10-23
I want the array to have three elements populated like:
arr[0] = 2017, arr[1] = 10, arr[2] = 23
This is the function:
/*
* return a array of the parts of date_string
*/
int * to_date_array(char *date_string)
{
int i = 0;
int f = 0;
char *tokens = strtok(date_string, "-"); /* get initial token */
static int arr[3] = {0, 0, 0};
char *ptr;
int val;
/* init static arr */
for (f = 0; f < sizeof(arr); f++)
arr[f] = 0;
/* do the split */
while (tokens != NULL) {
val = strtol(tokens, &ptr, 10);
arr[i++] = val;
tokens = strtok(NULL, "-");
}
/*
* for some reason arr becomes 12 elements long?
* I expected it to have 3 elements
*/
puts("func: to_date_array");
puts("------------------------");
for (f = 0; f < sizeof(arr); f++)
printf("arr[%d]: %d\n", f, arr[f]);
return arr;
}
The function works but I'm really puzzled by the "arr" array. I expect it to be three elements long but when I iterate through it and print every element, it show 12 elements?
$ gcc -Wall main.c arguments.c -o timespan
$ ./timespan 2015-08-10 2017-10-18
func: to_date_array
------------------------
arr[0]: 2015
arr[1]: 8
arr[2]: 10
arr[3]: 0
arr[4]: 0
arr[5]: 0
arr[6]: 0
arr[7]: 0
arr[8]: 0
arr[9]: 0
arr[10]: 0
arr[11]: 0
The sizeof operand returns a size in bytes (where by definition a char takes one byte). On your (and mine) machine, sizeof(int) is 4, hence an array of 3 int takes 12 bytes. See nucleon's answer.
Your to_date_array is not reentrant. It would be nicer to return a dynamically allocated array (e.g. with calloc ....). Of course you need then to adopt the convention that its result has to be later free-d (e.g. by the caller).
You could consider also returning a pointer to some struct ending with a flexible array member.
You could also pass arr (and its length) to the to_date_array and have it been filled by that function.
sizeof computes the size of the array in bytes, thus you have to divide by the size of a single element to get the number of elements, thus use
sizeof(arr)/sizeof(*arr)
sizeof returns the number of bytes in the array, not the number of elements. On your system, an int is 4 bytes wide, so the array takes up 12 bytes.
You need to divide the size of the array by the size of a single element to get the number of elements:
sizeof arr / sizeof *arr
C does not do any bounds checking on array access - the array is only three elements wide, but you won't get any sort of OutOfBounds exception if you attempt to access elements outside of that range. The behavior is undefined - your code may crash, it may produce unexpected results, it may work as intended, but the results won't necessarily be repeatable or predictable.
sizeof int arr[3] is sizeof(int) * 3 equals to 4*3 = 12

How does *(array + 3) work?

I am studying for my midterm. this was an example code
#include <stdio.h>
void doubleArray(int array[], int length)
{
for (int i = 0; i < length-2; i++) {
array[i] += array[i];
}
length += 5;
printf(“%d\n”, length); // Question 29
}
int main(int argc,char *argv[]) {
int integers[6] = { 3, 4, 5, 6, 7, 8};
int length = 6;
printf(“%d\n”, integers[4]); // Question 28
doubleArray(integers, length);
printf(“%d\n”, *(integers + 3)); // Question 30
printf(“%d\n”, *(integers + 4)); // Question 31
printf(“%d\n”, length); // Question 32
}
for questions 30 and 31
the answer is that it prints 12 (30) and 7 (31)
can someone explain to me why and what that "*(integers + 3)" means?
* is a dereference operator on a pointer.
This means that it will "get" the value that's stored at the pointer address of the item right after it ((integers + 3)).
It will interpret this value as the dereferenced type of the item after it (int since (integers + 3) is of type int*)
(integers + 3)
integers is a pointer to the address of the first element of the integers array.
That means that if integers contained [1, 2, 3, 4, 5] then it would point to where 1 is stored in memory.
integers + 3 takes the address of integers (i.e. where 1 is stored in memory) and adds the amount of address space required to store 3 ints (since the pointer is of type int*). Advancing it by one space would give you the address of 2 in memory, advancing it by two spaces would give you the address of 3 in memory, and advancing it by three spaces gives you the address of 4 in memory.
How this applies to your example
(integers + 3) gives you the address of the 4th item in the integers array since it's the first element's address plus the size of three elements.
Dereferencing that with the * operator, gives you the value of the 4th element, 12 (since the value of 6 was doubled by doubleArray)
The same applies to *(integers + 4) except that doubleArray didn't double the 5th element so it gives you 7.
How doubleArray works
for (int i = 0; i < length-2; i++) means start the variable i at 0 and advance it until it is length - 2.
This means it takes the value of everything from 0 to the value of length - 2 but executes the body of the loop for values from 0 to length - 3 since the < is exclusive (the conditional is evaluated BEFORE executing the body of the loop so when i == length - 2 the condition is false and the loop terminates without further execution.
So, for each element, excluding the last two, the element in array is added to itself.

Segmentation fault in function

When I run debugging it points to the line: 105 (and writes "segmentation fault" in the left corner). I don't know what does red line in "Call stack" window mean...
Please, tell waht it is and where can I read more about it.
Here is the function's code:
/* Separates stereo file's samples to L and R channels. */
struct LandR sepChannels_8( unsigned char *smp, unsigned long N, unsigned char *L, unsigned char *R, struct LandR LRChannels )
{
int i;
if ( N % 2 == 0 ) // Each channel's (L,R) number of samles is 1/2 of all samples.
{
L = malloc(N / 2);
R = malloc(N / 2);
}
else
if ( N % 2 == 1 )
{
L = malloc(N + 1 / 2);
R = malloc(N + 1 / 2);
}
int m = 0;
for ( i = 0; i < N; i++ ) // separating
{
L[m] = smp[2 * i + 0]; // THIS IS THE "LINE: 105"
R[m] = smp[2 * i + 1];
m++;
}
return LRChannels;
}
And here is sreenshot of the windows (easier to show it instead of trying to describe)
The line in red is your call stack: Basically, it's telling you that the problem occurred inside the the sepChannels_8() function, which was called from main(). You have, in fact, several bugs in your sepChannels_8() function.
Here is my analysis:
struct LandR sepChannels_8(unsigned char *smp, unsigned long N, unsigned char *L, unsigned char *R, struct LandR LRChannels)
sepChannels_8 is a function that takes five arguments of varying types and returns a value of type struct LandR. However, it's not clear what the five arguments passed to the function are. unsigned char *smp appears to be a pointer to your audio samples, with unsigned long N being the total number of samples. But unsigned char *L, unsigned char *R, and struct LandR LRChannels, it's not at all clear what the point is. You don't use them. unsigned char *L and unsigned char *R, your function promptly discards any passed-in pointers, replacing them with memory allocated using malloc(), which is then thrown away without being free()d, and the only thing you do with struct LandR LRChannels is simply return it unchanged.
{
int i;
if ( N % 2 == 0 ) // Each channel's (L,R) number of samles is 1/2 of all samples.
{
L = malloc(N / 2);
R = malloc(N / 2);
}
else
if ( N % 2 == 1 )
{
L = malloc(N + 1 / 2);
R = malloc(N + 1 / 2);
}
Now this is interesting: If the passed-in unsigned long, N, is an even number, you use malloc() to allocate two blocks of storage, each N / 2 in size, and assign them to L and R. If N is not even, you then double-check to see if it's an odd number, and if it is, you use malloc() to allocate two blocks of storage, each N in size, and assign them to L and R. I think you may have intended to allocate two blocks of storage that were each (N + 1) / 2 in size, but multiplication and division happen before addition and subtraction, so that's not what you get. You also fail to account for what happens if N is neither even nor odd. That's OK, because after all, that's an impossible condition... so why are you testing for the possibility?
int m = 0;
for ( i = 0; i < N; i++ ) // separating
{
L[m] = smp[2 * i + 0]; // THIS IS THE "LINE: 105"
R[m] = smp[2 * i + 1];
m++;
}
Mostly pretty standard: you've got a loop, with a counter, and arrays to traverse. However, your terminating condition is wrong. You're walking down your smp data two steps at a time, and you're doing it by multiplying your array index, so your index counter needs to run from 0 to N / 2, not from 0 to N. (Also, you need to account for that last item, if N was odd...). Further, you're using m and i for the same thing at the same time. One of them is unnecessary, and redundant, and not needed, and extra.
return LRChannels;
}
And, return the LRChannels struct that was passed in to the function, unmodified. At the same time, you're discarding the L and R variables, which contain pointers to malloc()-allocated storage, now lost.
What were L and R supposed to be? It almost looks as though they're supposed to be unsigned char **, so you could give your allocated storage back to the caller by storing the pointers through them... or perhaps struct LandR has two elements that are pointers, and you were intending to save L and R in the struct before returning it? for L and R, and LRChannels, I don't see why you're passing them to the function at all. You might as well make them all automatic variables inside the function just as int i and int m are.
You have malloced N/2 elements in the array but in the loop, your counter goes from 0 to N. And that will imply that you are trying to access elements from 0 to N because you increment m on every iteration. Obviously, you will get a seg fault.
What is the value of 'smp'?
It either needs to have been allocated prior to the call to sepChannels_8(), or point to a valid placeholder.

Allocate contiguous memory

I'm trying to allocate a large space of contiguous memory in C and print this out to the user. My strategy for doing this is to create two pointers (one a pointer to double, one a pointer to pointer to double), malloc one of them to the entire size (m * n) in this case the pointer to pointer to double. Then malloc the second one to the size of m. The last step will be to iterate through the size of m and perform pointer arithmetic that would ensure the addresses of the doubles in the large array will be stored in contiguous memory. Here is my code. But when I print out the address it doesn't seem to be in contiguous (or in any sort of order). How do i print out the memory addresses of the doubles (all of them are of value 0.0) correctly?
/* correct solution, with correct formatting */
/*The total number of bytes allocated was: 4
0x7fd5e1c038c0 - 1
0x7fd5e1c038c8 - 2
0x7fd5e1c038d0 - 3
0x7fd5e1c038d8 - 4*/
double **dmatrix(size_t m, size_t n);
int main(int argc, char const *argv[])
{
int m,n,i;
double ** f;
m = n = 2;
i = 0;
f = dmatrix(sizeof(m), sizeof(n));
printf("%s %d\n", "The total number of bytes allocated was: ", m * n);
for (i=0;i<n*m;++i) {
printf("%p - %d\n ", &f[i], i + 1);
}
return 0;
}
double **dmatrix(size_t m, size_t n) {
double ** ptr1 = (double **)malloc(sizeof(double *) * m * n);
double * ptr2 = (double *)malloc(sizeof(double) * m);
int i;
for (i = 0; i < n; i++){
ptr1[i] = ptr2+m*i;
}
return ptr1;
}
Remember that memory is just memory. Sounds trite, but so many people seem to think of memory allocation and memory management in C as being some magic-voodoo. It isn't. At the end of the day you allocate whatever memory you need, and free it when you're done.
So start with the most basic question: If you had a need for 'n' double values, how would you allocate them?
double *d1d = calloc(n, sizeof(double));
// ... use d1d like an array (d1d[0] = 100.00, etc. ...
free(d1d);
Simple enough. Next question, in two parts, where the first part has nothing to do with memory allocation (yet):
How many double values are in a 2D array that is m*n in size?
How can we allocate enough memory to hold them all.
Answers:
There are m*n doubles in a m*n 2D-matrix of doubles
Allocate enough memory to hold (m*n) doubles.
Seems simple enough:
size_t m=10;
size_t n=20;
double *d2d = calloc(m*n, sizeof(double));
But how do we access the actual elements? A little math is in order. Knowing m and n, you can simple do this
size_t i = 3; // value you want in the major index (0..(m-1)).
size_t j = 4; // value you want in the minor index (0..(n-1)).
d2d[i*n+j] = 100.0;
Is there a simpler way to do this? In standard C, yes; in C++ no. Standard C supports a very handy capability that generates the proper code to declare dynamically-sized indexible arrays:
size_t m=10;
size_t n=20;
double (*d2d)[n] = calloc(m, sizeof(*d2d));
Can't stress this enough: Standard C supports this, C++ does NOT. If you're using C++ you may want to write an object class to do this all for you anyway, so it won't be mentioned beyond that.
So what does the above actual do ? Well first, it should be obvious we are still allocating the same amount of memory we were allocating before. That is, m*n elements, each sizeof(double) large. But you're probably asking yourself,"What is with that variable declaration?" That needs a little explaining.
There is a clear and present difference between this:
double *ptrs[n]; // declares an array of `n` pointers to doubles.
and this:
double (*ptr)[n]; // declares a pointer to an array of `n` doubles.
The compiler is now aware of how wide each row is (n doubles in each row), so we can now reference elements in the array using two indexes:
size_t m=10;
size_t n=20;
double (*d2d)[n] = calloc(m, sizeof(*d2d));
d2d[2][5] = 100.0; // does the 2*n+5 math for you.
free(d2d);
Can we extend this to 3D? Of course, the math starts looking a little weird, but it is still just offset calculations into a big'ol'block'o'ram. First the "do-your-own-math" way, indexing with [i,j,k]:
size_t l=10;
size_t m=20;
size_t n=30;
double *d3d = calloc(l*m*n, sizeof(double));
size_t i=3;
size_t j=4;
size_t k=5;
d3d[i*m*n + j*m + k] = 100.0;
free(d3d);
You need to stare at the math in that for a minute to really gel on how it computes where the double value in that big block of ram actually is. Using the above dimensions and desired indexes, the "raw" index is:
i*m*n = 3*20*30 = 1800
j*m = 4*20 = 80
k = 5 = 5
======================
i*m*n+j*m+k = 1885
So we're hitting the 1885'th element in that big linear block. Lets do another. what about [0,1,2]?
i*m*n = 0*20*30 = 0
j*m = 1*20 = 20
k = 2 = 2
======================
i*m*n+j*m+k = 22
I.e. the 22nd element in the linear array.
It should be obvious by now that so long as you stay within the self-prescribed bounds of your array, i:[0..(l-1)], j:[0..(m-1)], and k:[0..(n-1)] any valid index trio will locate a unique value in the linear array that no other valid trio will also locate.
Finally, we use the same array pointer declaration like we did before with a 2D array, but extend it to 3D:
size_t l=10;
size_t m=20;
size_t n=30;
double (*d3d)[m][n] = calloc(l, sizeof(*d3d));
d3d[3][4][5] = 100.0;
free(d3d);
Again, all this really does is the same math we were doing before by hand, but letting the compiler do it for us.
I realize is may be a bit much to wrap your head around, but it is important. If it is paramount you have contiguous memory matrices (like feeding a matrix to a graphics rendering library like OpenGL, etc), you can do it relatively painlessly using the above techniques.
Finally, you might wonder why would anyone do the whole pointer arrays to pointer arrays to pointer arrays to values thing in the first place if you can do it like this? A lot of reasons. Suppose you're replacing rows. swapping a pointer is easy; copying an entire row? expensive. Supposed you're replacing an entire table-dimension (m*n) in your 3D array (l*n*m), even more-so, swapping a pointer: easy; copying an entire m*n table? expensive. And the not-so-obvious answer. What if the rows widths need to be independent from row to row (i.e. row0 can be 5 elements, row1 can be 6 elements). A fixed l*m*n allocation simply doesn't work then.
Best of luck.
Never mind, I figured it out.
/* The total number of bytes allocated was: 8
0x7fb35ac038c0 - 1
0x7fb35ac038c8 - 2
0x7fb35ac038d0 - 3
0x7fb35ac038d8 - 4
0x7fb35ac038e0 - 5
0x7fb35ac038e8 - 6
0x7fb35ac038f0 - 7
0x7fb35ac038f8 - 8 */
double ***d3darr(size_t l, size_t m, size_t n);
int main(int argc, char const *argv[])
{
int m,n,l,i;
double *** f;
m = n = l = 10; i = 0;
f = d3darr(sizeof(l), sizeof(m), sizeof(n));
printf("%s %d\n", "The total number of bytes allocated was: ", m * n * l);
for (i=0;i<n*m*l;++i) {
printf("%p - %d\n ", &f[i], i + 1);
}
return 0;
}
double ***d3darr(size_t l, size_t m, size_t n){
double *** ptr1 = (double ***)malloc(sizeof(double **) * m * n * l);
double ** ptr2 = (double **)malloc(sizeof(double *) * m * n);
double * ptr3 = (double *)malloc(sizeof(double) * m);
int i, j;
for (i = 0; i < l; ++i) {
ptr1[i] = ptr2+m*n*i;
for (j = 0; j < l; ++j){
ptr2[i] = ptr3+j*n;
}
}
return ptr1;
}

Resources