how can I use less variables in my program? - arrays

I had to make a program that have an array of numbers, and then I need to make a function that get the arr[0] and the length of the array, and then it will print all the numbers without the duplicate ones.
I made this program and it worked good but I feel like I used too much variables for this program. (I started to learned in the last few weeks so its not looks very good)
#include <stdio.h>
#define N 10
void print_set(int *arr, int n) {
int i = 1;
int duplicate_num, check_num, count;
printf(" %d", *arr); //printing the first number (arr[0]).
//starting to check the other number. if they new I'll print them. (start from arr[1]).
arr++;
while (i < n) {
if (*arr != duplicate_num) {
printf(" %d", *arr);
check_num = *arr;
// becouse I found new number, I change it no be equal to the first duplicate_num. (if there are more like him, I change them too).
while (i < n) {
if (*arr == check_num) {
*arr = duplicate_num;
}
arr++;
i++;
count++;
}
i = i - count;
arr = arr - count;
count = 0;
}
arr++;
i++;
}
}
int main() {
int arr[N] = {4, 6, 9, 8, 6, 9, 6, 1, 6, 6};
print_set(&arr[0], N);
return 0;
}
output for this program: 4 6 9 8 1
I'll be happy to see good method to make this program less messy.

For starters the function has undefined behavior. The user can pass 0 as the second argument. It means that the array is empty and has no elements. In this case the expression *arr is undefined.
The second problem is using the uninitialized variable duplicate_num in this if statement
if (*arr != duplicate_num) {
and the uninitialized variable count
count++;
Another problem is that the function changes the array
if (*arr == check_num) {
*arr = duplicate_num;
}
If you need only to output unique values in an array then the source array shall not be changed.
The function can be defined for example the following way
void print_set( const int *a, size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
size_t j = 0;
while ( j != i && a[i] != a[j] ) ++j;
if ( j == i ) printf( "%d ", a[i] );
}
putchar( '\n' );
}

Related

multi pointers in function in c

i'm not good at english.
i declare array and two pointers.
the maxPtr pointer should have array arr's maximum number adress.
and minPtr pointer should have array arr's minimum number adress.
so i declare the function and this has two double-pointer to give maxPtr and minPtr proper adress.
but whenever i run this code, the program is not fully run.
it doesn't output the result( printf("%d",*maxPtr) ,printf("%d", *minPtr, printf("Hi");
this program is run at vscode in mac.
what make it error?
#include <stdio.h>
void MaxAndMin(int* str,int** max, int** min)
{
int i;
int maxnum=0,minnum=0;
for(i=0; i<5; i++)
{
if(maxnum< str[i])
{
maxnum =str[i];
*max = &str[i];
}
if(minnum > str[i])
{
minnum = str[i];
*min = &str[i];
}
}
}
int main(void)
{
int i,len;
int* maxPtr;
int* minPtr;
int arr[5]={};
for(i=0; i<5; i++)
{
printf("%d번째 정수입력 입니다.",i+1);
scanf("%d", &arr[i]);
}
MaxAndMin(arr,&maxPtr,&minPtr);
printf("%d",*maxPtr);
printf("%d",*minPtr);
printf("Hi");
return 0;
}
the result is
> Executing task: ./test <
1번째 정수입력 입니다.1
2번째 정수입력 입니다.2
3번째 정수입력 입니다.3
4번째 정수입력 입니다.4
5번째 정수입력 입니다.5
Terminal will be reused by tasks, press any key to close it.
For starters this initialization of an array
int arr[5]={};
is incorrect in C. You have to write
int arr[5]={ 0 };
Secondly using the magic number 5 within the function makes the function useless in general. You need to pass to the function the size of the array.
The initial value 0
int maxnum=0,minnum=0;
of these variables makes the function even more less useful. In general the array can contain either all elements positive or all elements negative.
And you need to flush the output buffer using for example the new line character '\n' in calls of printf.
The function can be declared and defined the following way as it is shown in the demonstration program below.
#include <stdio.h>
void MaxAndMin( const int a[], size_t n, int **max, int **min )
{
*max = ( int * )a;
*min = ( int * )a;
for ( size_t i = 1; i < n; i++ )
{
if ( **max < a[i] )
{
*max = ( int *)( a + i );
}
else if ( a[i] < **min )
{
*min = ( int * )( a + i );
}
}
}
int main( void )
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const size_t N = sizeof( a ) / sizeof( *a );
int *maxPtr = NULL;
int *minPtr = NULL;
MaxAndMin( a, N, &maxPtr, &minPtr );
printf( "The maximum value is %d at position %tu\n",
*maxPtr, maxPtr - a );
printf( "The minimum value is %d at position %tu\n",
*minPtr, minPtr - a );
}
The program output is
The maximum value is 9 at position 9
The minimum value is 0 at position 0
Pay attention to that the first parameter of the function should have the qualifier const because passed arrays to the function are not changed within the function.
The main issue is that the minnum is set at zero, which would only work if array had a negative value.
Setting minimum = star[0] also would not work!!! Because in the case of str[0] having negative value, *min never gets changed.
Also, I recommend to always initialize all variables in the declaration, especially pointers (because they may theoretically cause accidental access to memory).
Full solution:
#include <stdio.h>
int MaxAndMin(int* str, int** max, int** min)
{
int i;
int maxnum = 0;
int minnum = str[0] + 1;
for(i=0; i<5; i++)
{
if(maxnum < str[i])
{
maxnum = str[i];
*max = &str[i];
}
if(minnum > str[i])
{
minnum = str[i];
*min = &str[i];
}
}
return 0;
}
int main(void)
{
int i = 0;
int len = 0;
int* maxPtr = NULL;
int* minPtr = NULL;
int arr[5]={};
for(i=0; i<5; i++)
{
printf("Enter number %d: ",i+1);
scanf("%d", &arr[i]);
}
MaxAndMin(arr, &maxPtr, &minPtr);
printf("%d",*maxPtr);
printf("%d",*minPtr);
printf("Hi");
return 0;
}

how to filter an array and overwrite that

I need to filter some specific elements from an array. I write the code which work perfectly:
#include <stdio.h>
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
int main (int argc, char *argv[]) {
// our initial array
int x[] = {1,2,-3,4,5};
// initialize filtered_array with pointer
int *filtered;
int upper_bound = 4, lower_bound = 1, i, j=0, total = -1,result;
size_t n = NELEMS(x);
printf("size of the main array: %d\n",n);
// check which element satisfy the condition and count them
for (i=0;i<n;++i)
{
total = ((x[i] >= lower_bound) && (x[i] <= upper_bound)) ? total+1 : total;
};
// allocate array size for filtered array
filtered = (int*) calloc(total,sizeof(int));
for (i=0;i<n;++i)
{
// filter element from main array and store them in filtered array
result = ((x[i] >= lower_bound) && (x[i] <= upper_bound)) ? 1 : 0;
if(result) {
filtered[j] = x[i];
++j;
};
};
for (i = 0; i<total+1; ++i){
printf("%d ",filtered[i]);
};
return 0;
}
But can I avoid to create a new array like I used filtered and dynamically do this for the main array by some overwrite trick?
For starters your program is incorrect.
Firstly you need to include the header <stdlib.h>
#include <stdlib.h>
Secondly, initially total is set to -1
total = -1
So if the original array contains only one element that satisfies the condition then total will be equal to 0 due to this statement
total = ((x[i] >= lower_bound) && (x[i] <= upper_bound)) ? total+1 : total;
As a result this statement
filtered = (int*) calloc(total,sizeof(int));
is trying to allocate a memory with the size equal to 0. If the memory will be allocated (it is implementation defined) then you may not write anything in this memory. Otherwise the program will have undefined behavior.
In any case you are counting elements that satisfy the condition incorrectly and hence allocating a block of memory of an incorrect size.
Also there is no sense to insert a null statement after compound statements as you are doing
for (i=0;i<n;++i)
{
//...
};
^^^
Remove such redundant semicolons.
And you are using an incorrect conversion specifier in this call of printf.
printf("size of the main array: %d\n",n);
^^^
You have to write
printf("size of the main array: %zu\n",n);
^^^
As for your question
But can I avoid to create a new array like I used filtered and
dynamically do this for the main array by some overwrite trick?
then what you need is to change the array in place and to track the number of actual elements that satisfy the condition.
For example
int x[] = {1,2,-3,4,5};
// initialize filtered_array with pointer
size_t n = NELEMS(x);
int upper_bound = 4, lower_bound = 1;
printf( "size of the main array: %zu\n", n );
size_t m = 0;
for ( size_t i = 0; i < n; ++i )
{
if ( x[i] >= lower_bound) && x[i] <= upper_bound )
{
if ( m != i )
{
x[m] = x[i];
}
++m;
}
}
for ( size_t i = 0; i < m; ++i )
{
printf( "%d ", x[i] );
}
putchar( '\n' );
If you need to reallocate the original array according to the number of elements that satisfy the condition then the code can look for example the following way
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//...
size_t n = 5;
int *x = malloc( n * sizeof( int ) );
memcpy( x, ( int[] ){ 1, 2, -3, 4, 5 }, n * sizeof( int ) );
int upper_bound = 4, lower_bound = 1;
printf( "size of the main array: %zu\n", n );
size_t m = 0;
for ( size_t i = 0; i < n; ++i )
{
if ( x[i] >= lower_bound) && x[i] <= upper_bound )
{
if ( m != i )
{
x[m] = x[i];
}
++m;
}
}
if ( m != n )
{
int *tmp = realloc( x, m * sizeof( int ) );
if ( tmp != NULL )
{
x = tmp;
for ( size_t i = 0; i < m; ++i )
{
printf( "%d ", x[i] );
}
putchar( '\n' );
}
}
free( x );
What you are looking for is called modification (in this case filtering) in place.
That's even pretty simple:
int* filter(int* begin, int* end)
{
int* pos = begin; // start at the beginning of the array
for(; begin != end; ++begin)
{
if(*begin != 0) // your appropriate condition!
// this one filters out all zero values...
{
*pos++ = *begin; // copy current element to retain into
// first position not yet used
// (pos always points to one element past
// the last one retained!)
}
}
return pos; // as above, points to one past the last element retained
}
The return value is important to know how many elements remained.
If you prefer, you can instead write an index-based variant avoiding pointer arithmetics...
The basic idea about the filtering algorithm is that you just copy the elements towards the front, overwriting those values that either are filtered away or have already been copied.
Edit: Additional explanations:
begin and end pointers are to be passed as pointer to first element of the array and pointer to one past the array (typical C++ semantics when iterating over C++ STL containers, though these come with their own iterator types instead of pointers...).
So you'd call the function like:
int array[N];
int* newEnd = filter(array, array + sizeof(array)/sizeof(*array));
This is typical C++ semantics when iterating over STL containers (though these come with their specific iterator types instead of poitners).
If you don't like:
size_t filter(size_t length, int array[length]) // note: length as array subscript
// is ignored anyway...
{
int* pos = array;
int* begin = array;
int* end = array + length;
// now following the identical loop as above
return pos - array; // pointer difference; if pos points one past the last
// element you get the *number* of elements retained
}
About *pos++ = *begin: That's nothing special and any good C book should explain that nicely to you...
It copies the value begin points to to the address pos points to and increments pos afterwards.
An indexing loop doing the same might look as follows:
size_t pos = 0;
for(size_t i = 0; i < length; ++i)
{
array[pos++] = array[i]
}
return pos;

How to identify an embedded palindrome within an array of digits

Say we have
int arr1[]={1,2,3,4,5};
int temp1[], temp2[];
and that we need to copy the first 3 members from arr1 to temp1, and the second 3 from arr1 to temp2, so that
temp1={1,2,3};
temp2={2,3,4};
and so on and so forth, how would you go on about doing it? I am trying to write a program to check if a user inputted number contains a palindrome in a length k (where k is also chosen by the user) and my idea was to store the number in an array, take the first 3 members, put them in an array, reverse them and put that in another array and then compare, but I am stuck on how to solve the problem I mentioned above, I tried something like:
void copyandReverse(int arr[], int copy[], int reverse[], int start, int length)
{
for(int i=0; i<length; i++)
{
copy[start+i]=arr[start+i];
reverse[start+i]=arr[start+length-i-1];
}
}
but it seems to only copy the first 3 elements, and reverse them.
PS: I don't think we're allowed to use string or dynamic memory allocation, it's given that the inputted number contains less then 10 digits, so I made the temporary arrays with a constant size 10.
There is no any need to create auxiliary arrays to check whether a given array is a palindrome.
This can be done much simpler.
Write a function like this
int is_palindrome( const unsigned int a[], size_t n )
{
size_t i = 0;
while (i < n / 2 && a[i] == a[n - i - 1]) ++i;
return i == n / 2;
}
then in main if you have an array like
unsigned int a[10];
and you need to check whether a sub-array with three elements is a palindrome then you can do this in a for loop
size_t k = 3;
for ( size_t i = 0; i <= 10 - k; i++ )
{
if ( is_palindrome( a + i, k ) )
{
printf( "The sub-array at position %zu:", i );
for ( size_t j = i; j < k + i; j++ ) printf( " %u", a[j] );
puts( " is a palindrome" );
}
}
as #stark mentioned, just iterate over the array with two indices.
Please see an example implementation below. You just need to evaluate the actual size from the userinput before you validate it.
The code below assumes 0 as the delimited. After gathering the actual user input size, we start a loop with index i and j. Looping until they have swapped positions.
If a mismatch exists, we return FALSE, otherwise TRUE.
#include <stdio.h>
#define TRUE 1
#define FALSE 0
size_t getUserInputLength(int *arr, size_t len)
{
for (size_t i = 0; i < len; i++)
{
if (arr[i] == 0)
{
return i;
}
}
return len;
}
int checkPalindrome(int *arr, size_t len)
{
size_t i, j;
for (i = 0, j = len - 1; i <= j; i++, j--)
{
printf("Current indices: [i: %ld, j: %ld]\n", i, j);
printf("Current values: [i: %d, j: %d]\n", arr[i], arr[j]);
if (arr[i] != arr[j])
{
return FALSE;
}
}
return TRUE;
}
int main()
{
// even number of user input
int evenInput[] = {1, 2, 3, 4, 3, 2, 1, 0, 0, 0};
size_t evenLen = getUserInputLength(evenInput, 10);
printf("Even number returned: %d\n", checkPalindrome(evenInput, evenLen));
// odd number of user input
int oddInput[] = {1, 2, 3, 2, 1, 0, 0, 0, 0, 0};
size_t oddLen = getUserInputLength(oddInput, 10);
printf("Odd number returned: %d\n", checkPalindrome(oddInput, oddLen));
return 0;
}

Void function: removing elements from an array?

I want to make a function that removes elements from an array.
I attempted making the function myself, however, not fully successful:
void remove_element(int* array, int number, int array_length)
{
int i, j;
for (i = 0; i < array_length; i++){
if (array[i] == number) {
for (j = i; j < array_length; j++)
array[j] = array[j+1];
array_length--;
}
}
}
first thing I noticed is after function is called in main, array_lenght is not changed, therefore length of an array remains the same after removing element(s).
So the first question is how to change length of an array inside the void function?
Second thing which doesn't work properly is if in an array are two or more same numbers next to each other, for example if array contains 1,1,3,4,5,6 and user wants to remove 1 function will remove only one element.
Example of my output (wrong):
1,1,3,4,5,6 after fucntion 1,3,4,5,6
Thanks
In the current signature you cannot modify the array, as returning the new array you also need to return the new length.
There are many ways to do it, here is a way with a single loop:
void
remove_element(int* array, int number, int *array_length)
{
int i, j;
for (i = 0, j=0; i < *array_length; i++) {
if (array[i] != number)
array[j++] = array[i];
}
*array_length = j;
}
Doing so, this will mutate both the initial array and the variable keeping its length in the caller and you must pass the value of array_length by reference, somthing like
int* some_array, some_array_length, n;
remove_element(some_array, n, &some_array_length)
Other method would be to return the new length and mutate the array or allocate a new array in the heap and return both the allocated array and the new length.
The other answers to your question aside, if you're likely to do more than one removal on average (or more than one per call ever, actually), it's better not to shift all the subsequent values again and again. Try this:
void remove_element(int *array, int number, int *array_length) {
for(int iRead = 0, iWrite = 0; iRead < *array_length; iRead++) {
if(array[iRead] == number)
continue; /* skip without increasing iWrite */
if(iWrite < iRead) /* it works without this line, too, what's better depends */
array[iWrite] = array[iRead];
iWrite++;
}
*array_length = iWrite;
}
How this works, e.g., with array = {1,1,2,2,3} and number = 2:
1 1 2 2 3
^ iRead
^ iWrite
(increases both, writes nothing)
1 1 2 2 3
^ iRead
^ iWrite
(increases both, writes nothing)
1 1 2 2 3
^ iRead
^ iWrite
(continue happens: increases only iRead)
1 1 2 2 3
^ iRead
^ iWrite
(continue happens: increases only iRead)
1 1 2 2 3
^ iRead
^ iWrite
(writes 3 to iWrite, increases both)
1 1 3 2 3
^ iRead = 5
^ iWrite = 3
(iRead is no longer < *array_length, loop stops, 3 == iWrite is the new length)
Based now on your Comments, I'll do it like this:
#include <stdio.h>
void remove_element(int number, int *arr, size_t *size);
int main(void){
int arr[] = {1,1,3,4,5,6};
long unsigned int arrSize;
int number = 1;
arrSize = sizeof arr / sizeof arr[0];
printf("Before:\n");
for ( size_t i = 0 ; i < arrSize ; i++ ){
printf("%d ", arr[i]);
}
printf("\nAfter:\n");
remove_element( number, arr, &arrSize );
for ( size_t j = 0 ; j < arrSize ; j++ ){
printf("%d ", arr[j]);
}
printf("\n");
}
void remove_element(int number, int *arr, size_t *size){
int arrTemp[*size];
long unsigned int j = 0,c;
for ( size_t i = 0 ; i < *size ; i++ ){
if ( arr[i] == number ){
continue;
}else{
arrTemp[j] = arr[i];
j++;
}
}
for ( size_t k = 0 ; k < j ; k++ ){
arr[k] = arrTemp[k];
}
c = j;
while ( *size > c ){
arr[c] = 0;
c++;
}
*size = j;
}
Output:
Before:
1 1 3 4 5 6
After:
3 4 5 6
By the way in your Question you said:
Examples of output:
1,1,3,4,5,6 after fucntion 1,3,4,5,6
And in your Comment you said:
It doesn't matter how many same numbers there are, in that case above if user wants to remove 1, all 1 's should be removed.
Please make up your mind.
Because array_length is not passed as pointer you're having copy of it on stack, so after you're getting outside of this function you're still having old value. You could use here memmove or memcpy instead of iteration over whole array after you find the same number. The reason why you didn't delete the next 1 in your array is, because when you're on i = 0 -> array[0] == 1, but when you move all of the numbers back then you move second 1 to array[0], without checking it afterwards because after you finished iteration you just increment i, without checking if what you moved to current value of array[i] is the same as previous one.
void remove_element(int *array, int number, int *array_length){
int sameValues = 0;
for(int i = 0; i < *array_length; i++){
while(array[i] == number){
*array_length--;
sameValues++;
}
if(sameValues > 0){
if(i < *array_length){
memmove(&array[i], &array[i + sameValues], (*array_length - i) * sizeof(int));
}
sameValues = 0;
}
}
}
To make it even more dynamic you could use realloc (and actually resize the space occupied by your array after you remove members, but then either you need to return new pointer or you need to point to pointer on your stack from where you call the function:
void remove_element(int **array, int number, int *array_length){
int sameValues = 0;
for(int i = 0; i < *array_length; i++){
while((*array)[i] == number){
*array_length--;
sameValues++;
}
if(sameValues > 0){
if(i < *array_length){
memmove(&(*array)[i], &(*array)[i + sameValues], (*array_length - i) * sizeof(int));
}
realloc(*array, *array_length);
sameValues = 0;
}
}
}
P.S. To use memmove you need to include string.h
When you declare an array the compiler will affect an amount of memory, and with array structure you can't change it. There is 2 solutions, change your array length but you still could access to the last "box" or redefine an array with the size wanted.
1st case :
void remove_element(int* array, int number, int * array_length){
int i = 0,j = 0;
while( i < *(array_length)-1){
if(array[i] == number && !find){
i++; //we step over
find = 1; //we find 1 element stop remove
}
array[j] = array[i];
i++;
j++;
}
*(array_length)--;
}
The int * array_length is a pointer to the memory, so your changes are keep when you go back in main. In your example, before remove_element array_length is equal to 6, and after it's 5. But you still could do array[5] (6th element cause notation 0 to 5 in c).
2nd case
int * remove_element(int * array, int number, int * array_length){
int * new_array = malloc((array_length -1) * sizeof(int)); // len - 1 cause we want to delet only 1 element
int i = 0;
int j = i;
int find = 0;
while( i < *(array_length)-1){
if(array[i] == number && !find){
i++; //we step over
find = 1; //we find 1 element stop remove
}
new_array[j] = array[i];
i++;
j++;
}
if (array[array_length] != number && !find){ //if we didn't find att all the element return array
return array;
} else {
*(array_length)--;
return new_array;
}
}
Here you have to return the new_array because int array[6] in your main is a constant : you can't change it with array = new_array.
Edit : yes of course when you don't need anymore your array you have to free it with free(array) (or it's automatically done at the end of the processus, but it's not proper code)
There is also a shorter method with addtion of pointers but it seems quite too complicated with your c lvl :)

Strange output from Counting Sort in C

I have the following Counting Sort function
/*
*File: countingSort.c
*Description: A counting sort subroutine. Takes as input an array of integers.
* an array length and a range. All values in the input array must fall within [0, range].
* Takes O(range + arrayLen) time and O(range + arrayLen) extra space
*
*/
#include "countingSort.h"
int* countingSort(int unsorted[], int arrayLen, int range) {
int store[range + 1];
int sorted[arrayLen];
for ( int i = 0; i <= range; i++ ) {
store[i] = 0;
}
for ( int i = 0; i < arrayLen; i++ ) {
sorted[i] = 0;
}
for ( int j = 0; j < arrayLen; j++ ) {
store[unsorted[j]] ++;
}
for ( int i = 1; i <= range; i++ ) {
store[i] += store[i-1];
}
for( int j = arrayLen - 1; j >= 0; j-- ) {
sorted[store[unsorted[j]]] = unsorted[j];
store[unsorted[j]] --;
}
return sorted;
}
The function is giving me really strange output. The output is nothing like the input most of the times but sometimes it just works.
Why is this happening?
I am calling it from another file called cSortTest.c.
That file looks like this
/*
*File: cSortTest.c
*Description: Tests countingSort.c
*
*/
#include <stdio.h>
#include "countingSort.h"
int main() {
int data[8] = { 2, 1, 9, 4, 4, 56, 90, 3 };
int* p;
p = countingSort(data, 8, 90);
for ( int i = 0; i < 8; i++ ) {
printf("%d Element: %d\n", i, *(p+i) );
}
}
You are returning a local array variable. This variable is destroyed when the function exits, making the address to it no longer safe or valid to access. In fact accessing it will give you what is called undefined behavior, which explains why it sometimes appears to "work".
This is a classic beginner's mistake in C. You must either have the caller pass in the desired destination array, or use malloc() to allocate "persistent" heap memory and return that:
int* countingSort(int unsorted[], int arrayLen, int range) {
int *sorted = malloc(arrayLen * sizeof *sorted );
if (sorted== NULL)
return NULL;
/* rest of sorting */
return sorted;
}
The arrayLen * sizeof *sorted expression computes the number of bytes required for the allocation. There's no need to use calloc() which clears the memory; you're going to overwrite each element so clearing it is just wasted effort.

Resources