I've written this function to remove count members from arr at index idx.
void remove_int(int (*arr)[], int idx, int count)
{
int i, j;
for (i = 0; i < count; i++)
for (j = idx; (*arr)[j]; j++)
(*arr)[j] = (*arr)[j+1];
}
I call it like this:
remove_int(&arr, index, cnt);
This works perfectly for local integers. Here's my problem. I have a header file like this:
struct {
/* other stuff */
char *array[100];
} global_struct;
Members in array are allocated and filled.
Someone figured I could just switch int to char and int (*arr)[] to char *(*arr)[], then call:
remove_char(&global_struct.array, index, cnt);
I tried it, but it doesn't actually modify global_struct.array. How should I change remove_int to work with global_struct.array?
global_struct.array is a pointer to char, and looks like it is intended to point to a string. So you need to change the function signature to something like:
void remove_strings(char *str[], size_t idx, size_t count);
I would suggest changing idx, count, i, and j to type size_t, as this is an unsigned integer type guaranteed to hold any array index. The size_t type has been available since C99.
Here is a demonstration program that incorporates a modified version of the remove_int() function:
#include <stdio.h>
struct {
char *array[100];
} global_struct;
void remove_strings(char *str[], size_t idx, size_t count);
int main(void)
{
global_struct.array[0] = "One";
global_struct.array[1] = "Two";
global_struct.array[2] = "Three";
global_struct.array[3] = "Four";
global_struct.array[4] = "Five";
global_struct.array[5] = NULL;
for (size_t i = 0; global_struct.array[i]; i++) {
printf("%s\n", global_struct.array[i]);
}
remove_strings(global_struct.array, 2, 2);
putchar('\n');
puts("After removal:");
for (size_t i = 0; global_struct.array[i]; i++) {
printf("%s\n", global_struct.array[i]);
}
return 0;
}
void remove_strings(char *str[], size_t idx, size_t count)
{
size_t i, j;
for (i = 0; i < count; i++)
for (j = idx; str[j]; j++)
str[j] = str[j+1];
}
Program output:
One
Two
Three
Four
Five
After removal:
One
Two
Five
Also, it appears that your function remove_int() only works on arrays of int that exclude 0 members, as 0 is used as a sentinel value in the inner loop of your function. It is common to terminate an array of pointers to char with a NULL pointer, as I have done, and of course a string is an array of chars terminated with a '\0'. But, it is not in general a good idea to terminate an array of ints with a zero. This feature of your code did make it a simple matter to adapt it to work with strings.
While your function may satisfy your current requirements, consider changing it to return the number of ints stored in the array. It makes sense to keep track of the number of ints stored in the array, and passing this value as an argument allows the function to iterate over the array without a sentinel value. Here is a revised version of your function:
size_t remove_ints(size_t idx, size_t count, int arr[], size_t arr_sz)
{
size_t i, j;
for (i = 0; i < count; i++)
for (j = idx; j < arr_sz; j++)
arr[j] = arr[j+1];
return arr_sz - count;
}
The purpose of "for (i = 0; i < count; i++)"?
As my understand I think you should:
void remove_int(int (*arr)[], int idx)
{
int j;
for (j = idx; (*arr)[j]; j++)
(*arr)[j] = (*arr)[j+1];
}
Related
This code has to copy one array to another via void copy function. But I don't understand why it doesn't work.
#include <stdio.h>
void copy(int func_array_1[], int func_array_2[], int size) {
for (int i = 0; i < size; i++)
func_array_1[i] = func_array_2[i];
}
int main() {
int size = 0;
int array[10] = { 0 };
int copy_array[10] = { 0 };
printf("Input the number of elements to be stored in the array :");
scanf("%d", &size);
for (int i = 0; i < size; i++)
scanf("%d", &array[i]);
copy(array, copy_array, size);
for (int i = 0; i < size; i++)
printf("%d", copy_array[i]);
return 0;
}
It gives first defined array members which are all zero.
for (int i = 0; i < size; i++)
func_array_1[i] = func_array_2[i];
You're copying from the zero-initialized array to the one you actually want to copy to.
So just change the loop body to:
func_array_2[i] = func_array_1[i];
Using const and / or more purposeful naming could've prevented your error.
You have a typo in the function
for (int i = 0; i < size; i++)
func_array_1[i] = func_array_2[i];
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
As the function is called like
copy(array, copy_array, size);
you have to write
for (int i = 0; i < size; i++)
func_array_2[i] = func_array_1[i];
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
The reason of the typo is a bad function declaration. The function should be declared at least like
void copy( const int func_array_1[], int func_array_2[], int size);
That is the array that is not being changed within the function should be declared with the qualifier const.
Instead of the for loop you could use the standard function memcpy declared in the header <string.h> as for example
memcpy( func_array_2, func_array_1, size * sizeof( int ) );
Pay attention to that you need to check that the entered value of the variable size is not greater than 10.
This is my current code:
#include <stdio.h>
int index_x[] = {0,0,1,0,1,0,0,0,1,0,0,1,0}; // any number of elements
int len = sizeof index_x / sizeof*index_x;
int main(void) {
int arr[len];
int j = 0;
for (int i = 0; i < len; i++)
if (index_x[i])
arr[j++] = i; // save and advance j only if value is "1"
for (int i = 0; i < j; i++) // only print below j !
printf("%d\n", arr[i]);
}
Output:
2
4
8
11
From this output, I would like to generate another array that is the difference between these elements. In this case the new array would be {2,4,3}. (2-4=2, 8-4=4, 11-8=3).
I am currently struggling with two things:
Saving the array generated from the current code arr[i] as a another array so I can manipulate it for future uses.
Generating the "differences array". The tricky part is that the number of elements will not be constant so I cannot specify an array size.
It may be helpful to break things out into functions.
int indexes_of_non_zero(int *source, size_t len, int **dest) {
*dest = malloc(sizeof(int) * len);
int count = 0;
for (int i = 0; i < len; i++) {
if (source[i] != 0) {
(*dest)[count++] = i;
}
}
*dest = realloc(*dest, sizeof(int) * count);
return count;
}
So we have a function indexes_of_non_zero that takes a source array of ints with size specified by argument len, and then a pointer to an array of ints that will be the destination for our output.
We can naively allocate the same amount of memory to the destination, then loop over the source array and store the indexes of non-zero elements. When we're done, we use count to know the size of destination array. We use realloc to shrink the array to just the needed size. And the key is we return the count so our main function knows how big the destination array is.
We can now create a diffs function to do basically the same thing for the differences.
int diffs(int *source, size_t len, int **dest) {
*dest = malloc(sizeof(int) * (len - 1));
for (int i = 0; i < (len - 1); i++) {
(*dest)[i] = abs(source[i] - source[i + 1]);
}
return len - 1;
}
Putting it all together (not copying and pasting the function implementations for terseness) with a main function, and remembering to free the memory we've used, we get:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int indexes_of_non_zero(int *source, size_t len, int **dest);
int diffs(int *source, size_t len, int **dest);
int main(void) {
int data[] = {0,0,1,0,1,0,0,0,1,0,0,1,0};
size_t len = sizeof(data) / sizeof(*data);
int *nz = NULL;
int *d = NULL;
int nzc = indexes_of_non_zero(data, len, &nz);
int dlen = diffs(nz, nzc, &d);
for (int i = 0; i < nzc; i++) {
printf("%d\n", nz[i]);
}
for (int i = 0; i < dlen; i++) {
printf("%d\n", d[i]);
}
free(nz);
free(d);
}
And compiling and running it, the output is:
2
4
8
11
2
4
3
I changed it to get the differences as direct as possible; the inner loop is very simple.
The size question, first part: I (still) tried to avoid size_t for the input but added some sanity check for the size. Just to show there is a limit.
part two: a first loop to get the sum of true values in advance. Also the booldata array consists of chars and is not called index_x. Index is i.
part three: the diffs VLA gets its exact size, which can be 0 even for huge inputs. Some test could be added here after counting, to rule out a (big) input full of "1".
I added the copying, with message and printout.
#include <stdio.h>
#include <string.h>
char booldata[] = { 0,0,1,0,1,0,0,0,1,0,0,1,0 };
char sz_overf = sizeof booldata > 0xffffL * 0xffff; // too-big-flag for exiting...
int len = sizeof booldata / sizeof * booldata; // ...to keep len below size_t
int sum_of_trues (char *booldata, int len) {
int sum = 0;
for (int i = 0; i < len; i++)
if (booldata[i])
sum++;
return sum;
}
void print_intarr(int *inta, int len) {
for (int i = 0; i < len; i++)
printf("%d\n", inta[i]);
}
int main(void)
{
if (sz_overf) return 100; // len might be overflowed
int unsigned // signed provokes VLA warning: 9 gazillions seems ok, but not 18
dsum = sum_of_trues(booldata, len) - 1; // Invest a counting loop
int diffs[dsum], // VLA
di = 0; // diffs' index
int sti = -1; // Stored last index containing true
for (int i = 0; i < len; i++)
if (booldata[i]) { // true?
if (sti >= 0) { // and is there a left neighbour?
int diff = i - sti; // how far away?
printf("%d\n", diff); // 1. on-the-fly result
diffs[di++] = diff; // 2. for keeps
}
sti = i; // remember last "true"
}
printf("Copying %zu bytes from Diff.-Array\n", sizeof diffs);
int diffscopy[sizeof diffs];
memcpy(diffscopy, diffs, sizeof diffs);
print_intarr(diffscopy, dsum); // dsum or sizeof diffs
return 0;
}
output:
2
4
3
Copying 12 bytes from Diff.-Array
2
4
3
The inner loop could look like this w/o multi-option:
if (booldata[i]) {
if (sti >= 0) // and is there a left neighbour?
diffs[di++] = i - st; // 2. for keeps
sti = i;
}
Two arrays and three variables. The rest is needed to make this work.
BUGS: all-false input segfaults. It takes one "true" to get zero diffs...
I'm playing and learning a little with C, created an array and passed it to a function together with its size so I can run through the array and print all its elements (so I gave the function two parameters: the array itself and its size).
But now I like to do all that just by passing one parameter to the function. I got it working a little by using a pointer but I don't know how to stop because I don't have any information about arrays length, it only works in the code below because I put the array length inside the for loop. But how would that work in general if I didn't know the size and only passed one parameter to the function?
I thought it might somehow be possible to realize if a pointer points outside of the array I'm currently working with, but is that even doable? :S
void printArray(int *p){
for(int i=0; i<4; i++){
printf("%d ", *(p+i));
}
}
int main(){
int myArray[4] = {8,4,1,1};
int *p = myArray;
printArray(p);
return 0;
}
The only way to traverse a pointed-to array without a length parameter is if the array contains a distinct terminator value.
For example, a C-string is "NULL-terminated" array of char values. You can traverse a char* because you know
to test for the presence of the '\0' character, which has an integer value of 0.
As it applies to the code in your question, you could use -1 as a terminator value, like so:
void printArray(int *p){
while (*p != -1{
printf("%d ", *p++);
}
}
Note however, that doing this requires that there is some way to interpret a valid int value as
"invalid" for your purposes.
In the main, it's much easier and simpler to just pass the length of the array to the function.
In addition to other mentioned approaches I can offer other two:
1) You can pass the length of array as the first element (like works some containers in Pascal):
#include <stdio.h>
void print_array(int *arr)
{
int length = arr[0];
for (int index = 1; index <= length; ++index)
printf("%d ", arr[index]);
printf("\n");
}
int main()
{
int length = 10;
int *arr = malloc(sizeof(int) * length);
arr[0] = length;
for (int index = 1; index <= length; ++index)
arr[index] = index * index * index;
print_array(arr);
free(arr);
return 0;
}
2) You can create a struct for your array (like is is done for std::vector in C++ STD with class):
#include <stdio.h>
typedef struct Array
{
int size;
int *data;
} Array;
void print_array(Array *arr)
{
for (int index = 0; index < arr->size; ++index)
printf("%d ", arr->data[index]);
printf("\n");
}
int main()
{
int length = 10;
Array *arr = malloc(sizeof(Array));
arr->data = malloc(sizeof(int) * length);
arr->size = length;
for (int index = 0; index < length; ++index)
arr->data[index] = index * index * index;
print_array(arr);
free(arr->data);
free(arr);
return 0;
}
I find this hard to explain but I'll do my best. I am passing an array to a function. I want to be able to grab the pointer of the array in the function and put the values of the array back into an array in the function.
If that doesn't make sense maybe this code will give you an idea of what I'm trying to attempt.
#define LENGTH 3
void FIR(short *filter) {
short temp[LENGTH] = {*filter, *(filter+1), *(filter+2)};
}
int main() {
short filter[LENGTH] = {1,2,5};
FIR(filter);
}
This code works but is quite ridiculous if the filter length is long. How could I do this for any length of filter array? Keep in my mind, I'm trying to preserve efficiency.
Use a loop, *(filter+x) is equivalent to filter[x]
#include <stdio.h>
#define LENGTH 3
void FIR(short *filter) {
short temp[LENGTH];
int i;
for(i = 0; i < LENGTH; ++i){
temp[i] = filter[i];
}
}
int main() {
short filter[LENGTH] = {1,2,5};
FIR(filter);
int i;
for(i = 0; i < LENGTH; ++i){
printf("%d ", filter[i]);
}
}
You can make your code look good by using loops or just use memcpy() to copy the whole array.
void FIR(short *filter)
{
short temp[LENGTH];
int i=0;
for(i=0;i<LENGTH;i++)
temp[i] = filter[i];
// or memcpy(temp,filter,sizeof(short) * LENGTH);
}
Since you talk about efficiency then go for the latter approach i.e. memcpy()
The most efficient approach is likely a memcpy. Since you know the type and size of the array.
#define LENGTH 3
void FIR(short *filter) {
short temp[LENGTH];
memcpy(temp, filter, sizeof(short)*LENGTH)
}
You could use memcpy(), or you could initialize your local array in a loop. For example,
void FIR(short *filter) {
short temp[LENGTH];
memcpy(temp, filter, LENGTH * sizeof(short));
}
or
void FIR(short *filter) {
short temp[LENGTH];
int i;
for (i = 0; i < LENGTH; i += 1) {
temp[i] = filter[i];
}
}
Other than memcopy(), one way is by using pointers:
void FIR(short *filter)
{
short temp[LENGTH], *tempP;
int i = 0;
tempP = temp;
while(LENGTH > i++) *tempP++ = *filter++;
}
If you want the length to be variable then use this
#include <stdio.h>
void FIR(short *filter, int length) {
short *temp = new short[length];
int i;
for(i = 0; i < length; ++i){
temp[i] = filter[i];
}
}
int main() {
short filter[3] = {1,2,5};
FIR(filter, 3);
int i;
for(i = 0; i < 3; ++i){
printf("%d ", filter[i]);
}
}
I am trying to pass a 2D array of variable size to a function to print it. I know how it's done when one has fixed sized arrays. But how does one do this with variable sized arrays? Here is some code that'll give you an idea what I am trying to do:
void print_grid(char (*g)[9], int size) // the array subscript (9 here) be variable
{
int i, j;
for (i=0; i<size; i++)
{
for (j=0; j<size; j++)
printf("%c ", g[i][j]);
printf("\n");
}
}
I'll call this function using the following code:
char a[3][3], b[9][9];
// assign a, b
print_grid(a, 3);
print_grid(b, 9);
Is there any way to do this without allocating any dynamic memory in print_grid()?
void print_grid(int rows, int cols, char g[][cols]) { ... }
void print_grid(char *g, int size)
{
int i, j;
for( i = 0; i < size; i++)
for( j = 0; j < size; j++)
{
printf("%c ", *(g + i*size + j));
printf("\n");
}
}
print_grid(a, 3);
When you pass an array in C it is always passed by reference, i.e. through a pointer. The type of this pointer is not pointer-to-array, but pointer-to-first-element. For example, the code generator will handle void f(char[][10]) as if it where void f(char*). The array dimensions are lost. The parser, however, will complain if it sees f declared twice so.
The motivation behind C was to have a powerful and portable assembler, not a new programming language. Multidimensional arrays are logical constructs that do not exist in the machine. Arrays are a way of thinking.
To pass the dimensions of arrays to functions C programmers traditionally use structs:
typedef struct array_tag {
int count;
char data[1]; /* actually data[count] */
} ARRAY;
typedef struct grid_tag {
int rows, columns;
char grid[1][1]; /* actually grid[rows][columns] */
} GRID;
void f(ARRAY* x)
{
int i;
for (i = 0; i < x->count; ++i) {
char c = x->data[i];
}
}
void g(GRID* x)
{
int i, j;
for (i = 0; i < x->rows; ++i)
for (j = 0; j < x->columns; ++j) {
char c = x->grid[i][j];
}
}
void h()
{
{
const int len = 100;
ARRAY* x = (ARRAY*) malloc(sizeof(ARRAY) + len * sizeof(char));
x->count = len;
f(x);
}
{
const int rows = 2, cols = 3;
GRID* x = (GRID*) malloc(sizeof(GRID) + rows * cols * sizeof(char));
x->rows = rows;
x->columns = cols;
g(x);
}
}
Yes, the malloc expression in this example allocates few bytes too much. Therefore the GNU-compiler supports arrays of zero length for a long time, which are not allowed in C90.
C99 has gone one step further with flexible arrays. From ISO/IEC 9899:1999, Section 6.7.2.1, paragraph 16: "As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member." In C99 the ARRAY and GRID types can be declared as:
typedef struct array_tag {
int count;
char data[]; /* actually data[count] */
} ARRAY;
typedef struct grid_tag {
int rows, columns;
char grid[][1]; /* actually grid[rows][columns] */
} GRID;
and you can
assert(1*sizeof(int) == sizeof(ARRAY));
assert(2*sizeof(int) == sizeof(GRID));
Many people think C arrays are quirky. But they're also an elegant solution which allows the declaration of indefinitely complex arrays. It is known as the "K&R array equation". A good explanation can be found here.
Hope this helps.
This one does it, assuming a squared grid:
void print_grid(void* g, int size)
{
char* my = (char*) g;
int i, j;
for (i=0; i<size; i++)
{
for (j=0; j<size; j++)
printf("%c ", my[i+j]);
printf("\n");
}
}
If you want to use non-squared grids, replace size with a rows and columns parameter and adjust counting: i<rows and j<columns.