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]);
}
}
Related
I am trying to make a program that first creates an array in another function, returns it and then calls another function that shuffles the contents of the array and returns it. However I am struggling to do this in C since I do not quite understand the array pointer system that has to be used here.
So far my code doesnt return the values 1-20 from makeArray() but instead returns an array full of 0s and I have a feeling it has to do with the c's array pointer system.
Any help would greatly be appreciated! Thank you in advance
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int arrShuffle();
int arrShuffle(int * arr) {
int arr[21];
// shuffle array
for(int j=0; j<20; j++) {
int randInd = (rand() % 20) + 1;
int temp = arr[j];
arr[j] = arr[randInd];
arr[randInd] = temp;
}
return arr;
}
int makeArray() {
int arr[21];
// make array of 1-20
for(int i=0; i < 20; i++) {
arr[i] = i + 1;
}
return arr;
}
void main() {
int *orgArr;
int *modArr;
srand(time(NULL));
orgArr = makeArray();
for(int i=0; i < 20; i++) {
printf("OrgArr: %d\n", orgArr);
}
modArr = arrShuffle(orgArr);
}
You cannot use variables with automatic storage (aka local ones). You must allocate the array so the memory remains valid after the function ends:
int* makeArray() {
int *arr = calloc(21, sizeof *a);
// make array of 1-20
for(int i=0; i < 20; i++) {
arr[i] = i + 1;
}
return arr;
}
Remember to release the array when it is no longer used:
int main() {
int *orgArr;
...
orgArr = makeArray();
...
free(orgArr);
}
As tstanisl pointed out in their answer, a possible solution is to use dynamic memory allocation. My answer, instead, will give you yet another solution: using an array passed by the caller.
NOTE: both solutions are valid and their usefulness depends on the specific needs of your program. There's no "right" universal solution.
void makeArray(int arr[], size_t len) {
for (size_t i = 0; i < len; i += 1) {
arr[i] = (int) (i + 1);
}
}
void cloneAndModifyArray(const int orig[], int new[], size_t len) {
for (size_t i = 0; i < len; i += 1) {
new[i] = orig[i] * 2; // or some other modification
}
}
And you use it like this:
#define ARR_LEN (100)
int main(void) {
int arr[ARR_LEN];
makeArray(arr, ARR_LEN);
int modified_arr[ARR_LEN];
cloneAndModifyArray(arr, modified_arr, ARR_LEN);
return 0;
}
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];
}
Here's what I'm trying to do:
I need a global array with a length that is dependent on a variable (NumOfRequests). That variable is set within a function. I don't think it's possible to declare a global array within a function as I tried to do in the following code:
static uint8 NumOfRequests;
typedef struct
{
uint16 IndexToRequest;
GdXRequestData_ts RequestData;
bool RequestSent;
} GdRequests;
static void SetupRequestStructures( void )
{
uint8 i;
for( i = 0; EepromData_ps.GD_Indices[i] != 0xFFFF; i++ )
{
NumOfRequests = i + 1;
}
GdRequests Requests[NumOfRequests];
for( i = 0; i < NumOfRequests; i++ )
{
Requests[i].IndexToRequest = EepromData_ps.GD_Indices[i];
}
}
It's not possible to declare an array and later decide what length it should be or change its length, as far as I know.
So does anyone know another solution for how to declare a global array with a length based on a variable that is set within a function?
Any feedback is appreciated. If you upvote or downvote, tell me why so I can improve with future questions.
You can use dynamic memory allocation to perform this task. Look at malloc and free. Here's a simple example of dynamic memory allocation on a global array of structs:
#include <stdio.h>
#include <stdlib.h>
typedef struct _MyStruct
{
int a;
int b;
} MyStruct;
MyStruct *g_Array = NULL;
void populatearray(MyStruct *array, int length)
{
int i;
for(i = 0; i < length; i++)
{
array[i].a = i;
array[i].b = i;
}
}
void printstructs(MyStruct *array, int length)
{
int i;
for(i = 0; i < length; i++)
{
printf("array[%d].a = %d\narray[%d].b = %d\n\n", i, array[i].a, i, array[i].b);
}
}
int main()
{
g_Array = malloc(50 * sizeof(MyStruct));
if(!g_Array)
{
puts("Malloc failed");
return 0;
}
populatearray(g_Array, 50);
printstructs(g_Array, 50);
free(g_Array);
return 0;
}
I'm using a for loop to create an 100 element array of char. I on the first run, I want to change all of its values to 1, the second run, I want its every second values to 0
char array[ 100 ] = { 0 };
int toggle_swith(char a[]) {
for (i = 0; i < 100; i++) {
printf(array[i] + "1 ");
}
}
int main( void ) {
int i;
for (i = 0; i < 100; i++) {
printf(array[i] + "0 ");
toggle_switch();
}
}
You need a function which initializes the array:
void InitializeArray(char Array[], int Length) {
int i;
for (i = 0; i < Length; i++) {
Array[i] = '1';
}
}
You need a function which changes every 2nd element:
void ChangeEverySecondElement(char Array[], int Length) {
int i;
for (i = 1; i < Length; i += 2) {
Array[i] = '0';
}
}
You need a function to print the array :
void PrintArray(char Array[], int Length) {
int i;
for (i = 0; i < Length; i++) {
putchar(Array[i]);
putchar(' ');
}
putchar('\n');
}
Then you need to put them together
int main() {
char Array[100];
InitializeArray(Array, 100);
PrintArray(Array, 100);
ChangeEverySecondElement(Array, 100);
PrintArray(Array, 100);
return 0;
}
If you are trying to learn C, I recommend the book I learned it from, C by Example written by Greg Perry.
you can do it all at once
for (i=0; i<100; i++) array[i]=(i%2)+'0';
a typical attempt at optimization could look like:
#define BUFSZ 100
int main(){
char buf[BUFSZ];
int *bp=(int *)&buf, i=(BUFSZ/sizeof(int));
/* handle aligned words 4 bytes at a time */
while (i) bp[--i]='0101'; /* for 64 bit use '0101'|('0101' <<32) */
/* handle unaligned bytes */
for(i=(BUFSZ/sizeof(int))*sizeof(int);i<BUFSZ;i++)buf[i]=1-i%2+'0';
write(1,buf,BUFSZ);
}
Initially you want to make all your array elements as 1
You can use memset
memset(array,1,100)
This will clear all elements. But if you insist on using a loop then,
#define ARRAY_SIZE 100
char array[ARRAY_SIZE] = {0};
for(int count = 0; count < ARRAY_SIZE; count++)
{
array[count] = 1;
//If you want to print it, use:
printf("%d",array[count]; // You can also use %c
}
To make alternate element 0,
for(int count = 0; count < ARRAY_SIZE; (count = count + 2)) //Count + 2 will hop every alternate element
{
array[count] = 0;
}
Again, You can add printf() if you want.
Print statement should look something like this.
printf("%c0",array[i]);
I suggest you look up Beginner C tutorial for more info.
None of the answers I have found seem to address my issue. I am creating a dynamic 3d array in C and later freeing it. I can store and later access the data stored in this array using a nested for loop but I get an access violation when trying to free it using the same nested for loop setup. Where am I going wrong?
unsigned char ***buff1;
int r, c;
someFunction(&buff1, &r, &c);
for(int i = 0; i < r; ++i)
{
for(int j = 0; j < c; ++j)
{
free(buff1[i][j]);
}
free(buff1[i]);
}
free(buff1);
someFunction(unsigned char**** buff, int *nR, int *nC)
{
...
*buff = (SQLCHAR***)malloc(*nR * sizeof(SQLCHAR**));
for(int i = 0; i < *nR; ++i)
{
(*buff)[i] = (SQLCHAR**)malloc(*nC * sizeof(SQLCHAR**));
for(int j = 0; j < *nC; ++j)
{
(*buff)[i][j] = (SQLCHAR*)malloc(256);
}
}
}
Multiple things are wrong:
unsigned char**** buff
What is this, if not wrong? (Well, OK, not technically, but stylistically anyway...)
(SQLCHAR*)malloc(256);
isn't any better either, since you must not cast the return value of malloc() in C.
The third mistake is that you don't have a 3D array. You have a pointer-to-pointer-to-pointer. Ewww. Ugly. Why not allocate a true 3D array instead?
size_t xsize, ysize, zsize; // initialize these!
unsigned char (*arr)[ysize][zsize] = malloc(sizeof(*arr) * xsize);
Then all you need to do in order to free it is:
free(arr);
Honestly, isn't this way better?
I try you code in this way,and it works good:
#include "stdio.h"
#include "stdlib.h"
int someFunction (unsigned char**** buff, int *nR, int *nC)
{
int i,j;
*buff = (unsigned char ***)malloc(*nR * sizeof(char**));
for(i = 0; i < *nR; ++i)
{
(*buff)[i] = (unsigned char**)malloc(*nC * sizeof(char**));
for(j = 0; j < *nC; ++j)
{
(*buff)[i][j] = (unsigned char*)malloc(256);
(*buff)[i][j][0] ='1';
}
}
}
int main()
{
unsigned char ***buff1;
int r = 3, c= 2,i,j;
someFunction(&buff1, &r, &c);
for( i = 0; i < r; ++i)
{
for(j = 0; j < c; ++j)
{
printf(" %c",buff1[i][j][0]);
free(buff1[i][j]);
}
free(buff1[i]);
}
free(buff1);
}
So, maybe the mistake is not happening in the code you are showing to us.
Your code looks pretty buggy. For starters you are calling someFunction(&buff1, &r, &c) while that function expects ints and not int *s. Later you dereference nR and nC and they aren't pointers.
I guess you should be getting some nasty warnings when compiling.