Input sequence contained in an array - c

I'm trying to implement this excercise but it doesn't work very well. It should tell me if the sequence in array B is contained in A. Any ideas? I have a problem getting it to work for every sequence.
#include <stdio.h>
#include <stdlib.h>
#define N 6
#define M 3
int contains(int v[], int n);
/*
*
*/
int main(int argc, char** argv)
{
int A[N], B[M];
int i, j = 0, flag = 0, contained = 1;
printf("Array A\n");
for (i = 0; i < N; i++)
{
printf("Insert element: ");
scanf("%d", &A[i]);
}
printf("Array B\n");
for (i = 0; i < M; i++)
{
printf("Insert element: ");
scanf("%d", &B[i]);
}
for (i = 0; i < (N - M + 1); i++)
{
flag = 0;
if (A[i] == B[j])
{
flag = 1;
j++;
}
if (flag == 0 && (i == N-M))
{
contained = 0;
printf("The sequence B is not contained in A!\n");
break;
}
}
if (contained == 1)
{
printf("The sequence B is contained in A\n");
}
return (EXIT_SUCCESS);
}

When you have a non match in the sequence, you never reset j so you start looking for the rest of the sequence starting to what ever value j was left at. Your program looks for the sequence B but doesn't require it to be contiguous.
You also don't check for when the sequence is completed so it for example B is at the start of A the j will keep incrementing and B[j] will overflow into unknown memory which is unlikely to match A so will give you an incorrect result. To fix this just check for when the whole of B is found and exit the loop.
Substituting the following will fix this:
if (j == M) break; // Break the loop when B sequence is found
if (flag == 0)
{
j = 0; // This was missing
if (i == N-M)
{
contained = 0;
printf("The sequence B is not contained in A!\n");
break;
}
}

For the third for loop when you're doing the check, you're (1) not actually checking every element of B against the corresponding element of A and (2) not checking the different start indices. What you probably meant to do is something like
for (i = 0; i < (N - M + 1); i++) {
for (j = 0; j < M; j++) {
if (A[i + j] != B[j]) {
break;
}
}
if (j == M) {
printf("Found a match!");
}
}

as your spinning through A if you find that an element of B does not match A then you need to set j back to 0

for (i = 0; i < (N - M + 1); i++)
{
int j;
for(j = 0; j < M; j++)
{
if(B[j] != A[j + i])
break;
}
/* sequence found */
if(j == M)
{
return true;
}
}
return false;

For searching B in A you may want to do something like following:
for (i = 0; i < (N - M + 1) ; i++)
if (A[i] == B[0])
{ j=0;
while (A[++i] == B[++j] && j<M);
break;
}
if (j == M)
{
printf("The sequence B is contained in A\n");
}
else{
printf("The sequence B is not contained in A\n");
}

GCC has the memmem() extention function (which is basically strstr(), but does not rely on NUL-terminated strings)
if (memmem(A, N * sizeof *A, B, M * sizeof *B)) {
printf("Found\n" );
} else {
printf("Not Found\n" );
}

Related

Block values that are smaller than the previous iteration

This loop checks the previous element in an array. The question is how can it be avoided to check the arr[0][0] with its previous element which causes undefined behavior?
Here is the code so far but it has this issue with the the first element being checked with its previous element.
int main()
{
int arr[2][4];
int k, n;
for (k = 0; k < 2; k++) {
for (n = 0; n < 4; n++) {
do {
printf("Provide a number");
scanf("%d", &arr[k][n]);
printf("This is %d in the position[%d][%d]\n", arr[k][n], k, n);
if (n==0) break;
printf("The arr[k][n] is %d and the arr[k][n-1] is %d and n-1 means %d\n", arr[k][n], arr[k][n - 1], n - 1);
} while (arr[k][n] <= arr[k][n - 1]); //Here is the issue
}
}
for (k = 0; k < 2; k++) {
for (n = 0; n < 4; n++) {
printf("%d\n", arr[k][n]);
}
}
}
The issue:
Adding the if (n==0) break; causes the program to allow adding smaller numbers than the ones inserted so far. While not including this line causes undefined behavior. How can this be fixed?
This is how it works now, which is not correct:
2 3 4 5
2 4 5 6
The printf statements are only for the purpose of viewing what is going on.
You only check with previous column. That is not related to your break but due to broken logic.
You could do it like this:
int main()
{
int arr[2][4];
int k, n;
int last_number, new_number;
for (k = 0; k < 2; k++) {
for (n = 0; n < 4; n++) {
do {
printf("Provide a number");
scanf("%d", &new_number);
printf("This is %d in the position[%d][%d]\n", new_number, k, n);
if (n==0 && k == 0)
break; // Don't check for increasing values.
} while (new_number < last_number);
arr[k][n] = new_number;
last_number = new_number;
}
}
for (k = 0; k < 2; k++) {
for (n = 0; n < 4; n++) {
printf("%d\n", arr[k][n]);
}
}
}
Change
while (arr[k][n] <= arr[k][n - 1]);
to
while (n > 0 && arr[k][n] <= arr[k][n - 1]);
This works because && short circuits the test when n == 0 and does not do the second test.
You will also need to fix the print statement.

Comparing two arrays in C ignoring the order of the elements inside each array

I want to compare two arrays in C, ignoring the order of the elements inside each array, I had two ideas to solve this problem.
Well, they're the same, to be honest. The first idea is to make a variable and increment it with 1 if we find our element inside the second table (please see the code below).
But this one doesn't work if we give it as an example {3, 2, 2, 1} {1, 2, 3, 4}.
the second idea (which I obviously couldn't code) is: setting a variable c=0 for example, after the first loop:
for (i = 0; i < n; i++) {
c = 0;
for (...
}
this c will count the number of fails
if (T1[i] != T2[j]) {
c += 1
}
Then before exiting the j loop, we check if c==n where n is the length of the table. Meaning we have n fails.
after that, unsetting cat the beginning of the i loop
this is my code:
#include <stdio.h>
int main() {
int n, i, j, c = 0;
printf("give the size of the first array: \n");
scanf("%d", &n);
int T1[n];
int T2[n];
// remplissage de T1
for (i = 0; i < n; i++) {
printf("give the value of %d case, table1: ", i + 1);
scanf("%d", &T1[i]);
}
// remplissage de T2
for (i = 0; i < n; i++) {
printf("give the value of %d case, table2: ", i + 1);
scanf("%d", &T2[i]);
}
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (T1[i] == T2[j]) {
c += 1;
break;
}
}
}
if (c == n) {
printf("True");
} else {
printf("False");
}
}
I think i've found what you are asking for.
You need to do two double for to check equality in both ways, and then compare those 2 numbers.
int c = 0;
for(int i = 0; i < 4; i++){
for(int y = 0; y < 4; y++){
if(A1[i] == A2[y]){
c += 1;
break;
}
}
}
int d = 0;
for(int i = 0; i < 4; i++){
for(int y = 0; y < 4; y++){
if(A2[i] == A1[y]){
d += 1;
break;
}
}
}
if(c != n || d != n || c != d){
printf("False");
}else{
printf("true");
}
If c and d are not the same it means that there is a duplicate that triggers 2 times the equal in one way.
If c and d are the same but not equal to the array size it means that there are no duplicates, but not all the elements of one array are in the other.
I hope i've been helpfull
With this approach
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (T1[i] == T2[j]) {
c += 1;
break;
}
}
}
the two arrays int T1[] = { 1, 1, 1, 1, 1 }; and int T2[] = { 1, 2, 3, 4, 5 }; will be always equal.
Also the approach with two pairs of such nested for loops where the arrays are swapped in the if statement will not help. In this case for example these arrays int T1[] = { 1, 2, 2, 2 }; and int T2[] = { 1, 1, 1, 2 }; again will be equal.
If you are allowed to sort arrays then you should sort the both arrays and compare them.
Otherwise you can use the approach shown in the demonstration program below.
#include <stdio.h>
int main( void )
{
enum { n = 5 };
int a1[n] = { 1, 2, 3, 2, 1 };
int a2[n] = { 3, 2, 2, 1, 1 };
int equal = 1;
for (size_t i = 0; equal && i < n; i++)
{
size_t count = 1;
for (size_t j = 0; j != i; j++)
{
if (a1[i] == a1[j]) ++count;
}
for (size_t j = 0; count && j < n; j++)
{
if (a2[j] == a1[i]) --count;
}
equal = count == 0;
}
printf( "The arrays are %sequal.\n", equal ? "" : "not " );
}
The program output is
The arrays are equal.
Your approach fails if there are duplicates in the first array: { 0, 0 } will compare equal to { 0, 1 }. If you were to compare T1 and T2 both ways, you would still have this counter example: { 0, 0, 1 } and { 0, 1, 1 }.
You can work around this problem by counting the number of occurrences in both arrays of each element in one of the arrays: the arrays contain the same numbers if all counts match:
#include <stdio.h>
int count(int val, const int *T, int n) {
int c = 0;
for (int i = 0; i < n; i++)
c += (T[i] == val);
return c;
}
int main() {
int n, i;
printf("give the size of the first array: \n");
if (scanf("%d", &n) != 1)
return 1;
int T1[n];
int T2[n];
// remplissage de T1
for (i = 0; i < n; i++) {
printf("give the value of %d case, table1: ", i + 1);
if (scanf("%d", &T1[i]) != 1)
return 1;
}
// remplissage de T2
for (i = 0; i < n; i++) {
printf("give the value of %d case, table2: ", i + 1);
if (scanf("%d", &T2[i]) != 1)
return 1;
}
for (i = 0; i < n; i++) {
if (count(T1[i], T1, n) != count(T1[i], T2, n))
break;
}
if (i == n) {
printf("True\n");
} else {
printf("False\n");
}
return 0;
}
The above code has a time complexity of O(n2) because of the nested loops. You pay get better performance for large n by sorting both arrays and comparing them sequentially (complexity O(n.log(n)).)

two strings of integers. Check if the second one is substring

#include <stdio.h>
int main() {
int x[100], y[100], i, j, dim1, dim2, subsir=0;
scanf("%d", &dim1);
for(i=0; i<dim1; i++)
{
scanf("%d", &x[i]);
}
scanf("%d", &dim2);
for(j=0; j<dim2; j++)
{
scanf("%d", &y[j]);
}
if(dim1<dim2)
{
printf("no");
return 0;
}
for(i=0; i<dim1; i++)
for(j=0; j<dim2; j++)
{
if(x[i]==y[j])
subsir=1;
}
if(subsir==1)
{
printf("yes");
}
else
{
printf("no");
}
return 0;
}
Consider two strings of integers. Check if the second string is a substring of the first in C.(the substring consists of consecutive elements of the first string)
You can achieve your goal with a brute force approach, trying every position from 0 to dim1 - dim2.
Here is a modified version with error checking:
#include <stdio.h>
int main() {
int x[100], y[100], i, j, dim1, dim2;
if (scanf("%d", &dim1) != 1 || dim1 > 100)
return 1;
for (i = 0; i < dim1; i++) {
if (scanf("%d", &x[i]) != 1)
return 1;
}
if (scanf("%d", &dim2) != 1 || dim2 > 100)
return 1;
/* no need to read second array if larger */
if (dim1 < dim2) {
printf("no\n");
return 0;
}
for (j = 0; j < dim2; j++) {
if (scanf("%d", &y[j]) != 1)
return 1;
}
/* trying every possible sub-array start in array `x` */
for (i = 0; i <= dim1 - dim2; i++) {
/* compare all entries */
for (j = 0; j < dim2; j++) {
if (x[i + j] != y[j])
break;
}
/* if above loop completed, we have a match */
if (j == dim2) {
printf("yes\n");
return 0;
}
}
printf("no\n");
return 0;
}
A possible implementation, based on your approach:
// this function will return `1` in case `arr2` is contained inside `arr1`, otherwise `0`
int is_subarr(int arr1[], size_t arr1_len, int arr2[], size_t arr2_len) {
// as you already did, we first check that arr1's len is not smaller than arr2's
if (arr1_len < arr2_len) {
return 0;
}
// useful check: in many implementations, when `arr2` is empty, they return true
if (arr2_len == 0) {
return 1;
}
// first loop: we go through all elements of `arr1` (but we stop when we have less elements left than `arr2`'s len)
for (size_t i = 0; i < arr1_len && i < arr2_len; i += 1) {
// temporary flag, we just pretend that `arr2` is contained, and then we check for the opposite
int eq = 1;
// starting with the current position `i` inside `arr1`, we start checking if `arr2` is contained
for (size_t j = 0; j < arr2_len; j += 1) {
// if it's not contained, we break from this inner loop, and we keep searching through `arr1`
if (arr1[i + j] != arr2[j]) {
eq = 0;
break;
}
}
// in case `arr2` is effectively found, we return `1`
if (eq == 1) {
return 1;
}
}
return 0;
}
NOTE: "strings of integers" are called "arrays of integers" in C; a "string" is an "array of chars", instead.

Inserting elements to array in C

My task is: If we look at any two neighbour values in an array, if the one on the right is two times greater than the one on the left, their average should be inserted between them and the new array consisting of old and new elements should be printed. I have a problem with moving the other elements after average.And using special functions or libraries is not allowed.I am beginner, and I hope you could help.
#include <stdio.h>
int main() {
int n, i, j;
double a[100], average;
printf("Enter the number of elements: ");
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%lf", &a[i]);
}
for (i = 0; i < n; i++) {
if ((a[i + 1] / a[i]) == 2) {
for (i = j = 0; i < n; ++i)
b[j++] = a[i];
if (a[i + 1] / a[i] == 2)
average = (a[i + 1] + a[i]) / 2;
b[j++] =average;
}
}
for (i = 0; i < j; ++i) {
printf("%lf\n", b[i]);
}
}
A simple way to solve your problem is adding double b[199];, and copying everything over:
for (i = j = 0; i < n; ++i) {
b[j++] = a[i];
if (...) b[j++] = ...; /* Append the average to b. */
}
for (i = 0; i < j; ++i) {
printf("%lf\n", b[i]);
}
If you really want to move the elements forward within a itself, then you can do it by adding an inner for loop (and an additional loop variable int k;) which copies the elements one-by-one:
for (k = n++; k > i; --k) {
a[k] = a[k - 1];
}
In order to insert an element in an array, you must copy the elements with higher index from the last one down.
Also avoid dividing by a[i] that can be zero, and properly handle 0,0 that match the criteria for inserting the average, and skip the inserted value to avoid inserting more zeros.
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, i, j;
printf("Enter the number of elements: ");
if (scanf("%d", &n) != 1 || n <= 0)
return 1;
double *a = malloc(sizeof(*a) * (2 * n - 1)); // allocate the array to the maximum size
if (a == NULL)
return 0;
for (i = 0; i < n; i++) {
if (scanf("%lf", &a[i]) != 1)
return 1;
}
for (i = 1; i < n; i++) {
if (a[i] == a[i - 1] * 2) {
for (j = n; j > i; j--)
a[j] = a[j - 1];
a[i] = (a[i - 1] + a[i]) / 2;
n++; // increase number of elements
i++; // skip the new value
}
}
for (i = 0; i < n; ++i) {
printf("%f\n", a[i]);
}
free(a);
return 0;
}
To insert an element in a specific position you would need to move the rest of the array. However doing it many times is expensive and you may prefer to use an array to store the position at which you want to insert the elements and then insert them all at once.
Alternatively you can create a new array where to copy the original plus the new values.
However there's an easier and faster way, that is adding the new values straight away, while you fill the original array. Here's a program that does that.
#include <stdio.h>
#define SIZE 100
int main() {
int i, n, avg = 0;
double a[SIZE];
while( puts("Enter the number of elements:") && (scanf("%d", &n) != 1 || n < 1 || n > SIZE) );
scanf("%lf", &a[0]);
for(i = 1; i < n+avg && i < SIZE-1 && scanf("%lf", &a[i]) == 1; i++) {
if( a[i] == a[i-1] * 2 ) {
a[i+1] = a[i];
a[i] = (a[i] + a[i-1]) / 2;
++avg;
++i;
}
}
for(i = 0; i < n+avg; i++) {
printf("%lf\n", a[i]);
}
return 0;
}

removing duplicate integers from an array in C

I am working on a program that removes duplicate values from an array by ordering it and then removing duplicate, consecutive values. First I execute a selection sort sorting method, and then call a function removedup() that modifies the array and returns the size. Then I basically print the values in the array up to that size. However, when I execute it, it only prints the original array and then a bunch of blank space. Does anyone know why this is occurring?
My code: http://pastebin.com/uTTnnMHN
Just the de-duplication code:
int removedup(int a[])
{
int i, count, j;
count = n;
for (i = 0; i < (n - 1); i++) {
if (a[i] == a[i + 1]) {
for (j = 0; j < (n - i); j++) {
a[j] = a[j + 1];
}
count--;
i--;
}
}
return count;
}
-1 for(j=0;j<(n-i);j++)
Is your loop to shift left your array (thus removing the duplicate value), j should not be init to j but to i, and the condition does not seem right
A correct one could be:
for(j=i;j<n-1;j++)
{
a[j]=a[j+1];
}
a[n-1] = 0; // Because you shift your table to the left, the last value should not be used
first if i=0 and if a[i]==a[i+1] then i=-1
for(i=0;i<(n-1);i++)
{
if(a[i]==a[i+1])
{
for(j=0;j<(n-i);j++)
{
a[j]=a[j+1];
}
count--;
i--; //i=-1 if(a[i]==a[i+1]) && if(i==0)
}
}
In your duplicate removal function, you need to start the moving loop at i, as has been mentioned, and you must use count - 1 as the loop bound for both loops, otherwise you will have an infinite loop whenever there are duplicates, because then a[n-2] == a[n-1] always after the first moving loop.
int removedup(int a[])
{
int i, count, j;
count = n;
for(i = 0; i < (count-1); i++)
{
if(a[i] == a[i+1])
{
for(j = i; j < (count-1); j++)
{
a[j]=a[j+1];
}
count--;
i--;
}
}
return count;
}
works correctly.
Since you're creating another array anyway, why not simplify your function?
int removedup(int a[], int b[])
{
int i;
int count = 1;
b[0] = a[0]
for(i=1;i<(n-1);i++){
if(a[i-1] != a[i]){
b[count++] = a[i];
}
}
return count;
}
Then when you call the function,
count=removedup(a, OutArray);
int removedup(int a[])
{
int i;
count = n;
for (i = 0; i < (count-1); ++i) {
if (a[i] == a[i+1]) { /* found a duplicate */
int d = 0; /* count the duplicates */
do {
++d;
} while ((i+1+d) < count && a[i] == a[i+1+d]); /* probe ahead again for a duplicate */
/* at this point we have either run out of duplicates or hit the end of the array */
if ((i+1+d) < count)
memmove(&a[i+1], &a[i+1+d], sizeof(int)*(count-(i+1+d))); /* shift down rest of the array if there's still elements to look at */
count -= d; /* adjust the count down by the number of duplicates */
}
}
return count;
}
what about this one,without sort but traverse.finally print the effective values of the array and return its size.
int removedup(int a[])
{
int i, count, j;
count = n;
int b[n];
memset(b,0,sizeof(b));
for (i = 0; i < (n - 1); i++)
{
if (-1 != b[i])
{
for(j=i+1;j<n-1;j++)
{
if( a[i]==a[j])
{
b[j]=-1;
count--;
}
}
}
}
for(i=0;i<n-1;i++)
{
if(-1 != b[i])
{
printf("%d ",a[i]);
}
}
return count;
}

Resources