0

I am trying to implement a function that's called Sniffer which gets two inputs and returns the correspond matrix.

First input is an integer binary array values (just zeros or ones)

second input is your searched word ( the word you choose it as argument to your function )

The functionally of the function :

Searching for occurrence of the given word within your given binary array. At each occurrence of your word there's always follows 8 bits following it, assume that always the input is correct (it means that there's no possibility two occurrence occur one after the other without at least there's space 8bits (8 binary values)!).

Then the function must return a matrix(integer matrix) of those followed 8bit for each occurrence of the word sorted corresponded by every row of the matrix. (the functions returns just the first 8bit followed each occurrence of the Searched word)

This means:

First row has first 8 followed bit on first occurrence of the word.
Second row has first 8 followed bit on second occurrence of the word.
Third row has first 8 followed bit on third occurrence of the word.
Fourth row has first 8 followed bit on fourth occurrence of the word.
etc ...

I will elaborate by examples: function structure is Code:

int ** SnifferPattern(int* givenArray , int* SearchedWord);
//it returns the corresponded matrix so used int** ;

example 1:

givenArray = {1,0,1,0,1,1,1,1,1,1,1,1,0,0};
SearchedWord = {1,0,1,0}; 

so the function returns a matrix(size 1x8 - 8 corresponds to 8followed bit) 
the first row is {1,1,1,1,1,1,1,1}, which is the first 8 bit followed 
the word 1010 the matrix here with one row because there's just 
one occurrence of the `SearchedWord` in the given array.

example 2:

givenArray = {1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,0,1,0,1,0};
SearchedWord = {1,1,0,0} 

so the function returns a matrix the first row is {1,1,1,1,1,1,1,1} 
which is the first 8 bit followed the word 1010 for the first occurrence. 
for the second occurrence we see the word appear , so the second row of 
the returned matrix(size 2x8) will include the first 8bit followed the 
word 1010 of the second occurrence. so second row of the matrix 
is {1,0,1,0,1,0,1,0} so the returned matrix (size 2x8) has two rows 
(because there's two occurrences of the SearchedWord) which each row 
corresponds to each occurrence of the SearchedWord.

example 3:

givenArray = {1,1,1,0,1,1,1,1,1,1,1,1,0,0}; 
SearchedWord = {0,1,0} 

so the function returns a matrix zero row (like an array with zero values) 
size 1x8 (8 columns is corresponded to 8followed bit). There's no 
occurrence of the SearchedWord within the givenArray so we return a zero 
matrix. There's no overlap between the occurrences of the searchedWords ,
so we assume always correctness of input.

I will explain my algorithm (a pleasure if there's another suggestions more compatible to my case)

My algorithm is searching for the word at every occurrence and then take at every occurrence the first followed 8bit. I take them and store them in a matrix's rows. But it sounds much hard to complete with this.

what I succeeded / tried to implement in C is this:

int ** SnifferPattern(int* s ; int* w)
{
    // s is the given array, w is the searched Word , number occurrences      
    // here 2 , so it should be two prints on the output of the program.
    int n;         
    int a[1000];    
    int i=0;        
    int j;          
    int k = 0;      
    int l;         
    int found = 0;  
    int t = 0;      
 
    a[k++] = i; 
    j = 0;       
    for (i = 0; i < k; i++) 
    {
        n = a[i] - j;   
        if (n == (sizeof(w)/sizeof(w[0]))) 
        {
            t = 0;
            for (l = 0; w[l]; l++)  
            {
                if (s[l + j] == w[l])
                {
                    t++;  // Matched a character.
                }
            }
            
            if (t == (sizeof(w)/sizeof(w[0]))) 
            {
                found++;  // We found a match!
                printf("word occurred at location=%d \n", j);  // Pint location
            }
        }
        j = a[i] + 1; 
    }
}

int main() {

    int s[1000] = {1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1};
    int w[1000] = {1,0,1}; 
    
    // s is the given array, w is the searched Word , number occurrences      
    // here 2 , so it should be two prints on the output of the program.
    
    SnifferPattern(s , w)
    
   //I should print all the matrix's row in the main function .
    return 0;
}
IrAM
  • 1,720
  • 5
  • 18
LiamLony
  • 51
  • 5
  • you need to edit your post a lot – IrAM Jan 02 '21 at 09:06
  • @lrAm edited, I believe now is better – LiamLony Jan 02 '21 at 09:09
  • look at [this](https://stackoverflow.com/posts/65528056/revisions) edit before and after. make it readable by using using proper spacing/tags and small paragraphs – IrAM Jan 02 '21 at 09:11
  • What do you return if `word[] = {1,0,1};` and `array[] = {1,1,1,1,1,1,0,1};` The pattern occurs, but nothing follows it in the array? – David C. Rankin Jan 02 '21 at 09:33
  • I am not sure you can call an array of integers as matrix, what you are trying is just returning part of the 1-D array, i don't see any other dimensions – IrAM Jan 02 '21 at 09:33
  • @IrAM Since the return will always have 8-elements, you would declare a pointer to array, `int (*foo)[8];` and allocate the number you need returning the pointer to the allocated block. (if I understand the problem) – David C. Rankin Jan 02 '21 at 09:36
  • @lrAm if there's more than one occurrence then the matrix is two dimension array – LiamLony Jan 02 '21 at 09:39
  • @DavidC.Rankin what do you mean? there's no need for dynamic allocation .. – LiamLony Jan 02 '21 at 09:40
  • What I understand is you have two parameters, the `word` array to search for in the `search` array. How do you expect the result to get back to the caller? Where does your `1x8` or `2x8`, etc.. array come from? Your function return type is `int **` but where does the storage for that come from? (-- or do you just want to output the results from the function and not return anything?? -- if so, why is the function return `int**`?) – David C. Rankin Jan 02 '21 at 09:47
  • exactly. it returns a matrix because I want at each row of the matrix it stores the correspond occurrence i.e first occurrence storing it in first row of the matrix, second occurrence in the second row of the matrix (if found) , third occurrence ..storing it in third row's matrix (if found) ..etc – LiamLony Jan 02 '21 at 09:52
  • How do you determine the length of your arrays? I mean, both `s` and `w` have a size of 1000, but the actual length of these arrays is much smaller. Determining the length with `sizeof(w) / sizeof(w[0])` will not work in your sniferfunction, where the paraterets `s` and `w` have "decayed" into pointer to the first elements of the arrays in `main`. You will need either an explicit length parameter for each array or you must use a special end marker, perhaps −1. – M Oehm Jan 02 '21 at 09:53
  • this is the maximum size 1000 ( I assumed that..it's doesn't matter ..not my issue) – LiamLony Jan 02 '21 at 09:56
  • I'd say it does matter. What's the length of `w` -- 3? 1000? What `sizeof(w) / sizeof(w[0])` tells you in `SnifferPattern`, which probably is 1 or 2, depending on your platform? – M Oehm Jan 02 '21 at 10:04
  • @LiamLony, i tried my level best to edit the question as its very long, update on top of my edit, if aything is missing. – IrAM Jan 02 '21 at 10:17
  • Okay, but understand in C, `int**` is just a single pointer (to a pointer). To make use of it, you must allocate for the number of pointers (the rows in your matrix you want to return). Then you must allocate column number of integers for each "occurrence" and assign the beginning address to one of the allocated pointers. That allows you to return the pointer-to-pointer and then index it as a 2D array (e.g. `matrix[x][y]` where `x` is the wanted row and `y` the column). Which if you know that you have 8-columns in every row is why I proposed a pointer-to-array (single allocation, single free) – David C. Rankin Jan 02 '21 at 10:51

2 Answers2

2

I think I have figured out what you need. And, as stated in your question ("at each occurrence of your word there's always follows 8 bits"), the following requires that a least 8-integers follow any match of w in s. Since you will include 8-integers in each row of the matrix you return, then using a pointer-to-array-of int[8] allows a single free() of the result in the caller.

Your sniffer function will loop over each integer in s keeping a counter index (ndx) of each time an integer in w matches the integer in s. When ndx equals the number of elements in w a match has been found and the next 8 integers are are collected as the columns in that row of your matrix using next8 as the index. You could write your sniffer function as:

#define AFTER    8

/* function returning allocated pointer to array of 8 int, *n of them */
int (*sniffer (int *s, int selem, int *w, int welem, int *n))[AFTER]
{
    int ndx = 0,                    /* match index */
        next8 = AFTER,              /* counter for next 8 after match found */
        found = 0,                  /* number of tiems w found in s */
        (*matrix)[AFTER] = NULL;
    
    for (int i = 0; i < selem; i++) {           /* loop over each int in s */
        if (next8 < AFTER) {                    /* count if next8 less than AFTER */
            matrix[found-1][next8++] = s[i];    /* set next8 index in matrix row */
        }
        else if (s[i] == w[ndx]) {              /* if s[i] matches w[ndx] */
            if (++ndx == welem) {               /* increment ndx, compare w/welem */
                /* allocate storage for next row in matrix */
                if (!(matrix = realloc (matrix, (found + 1) * sizeof *matrix))) {
                    perror ("realloc-matrix");  /* on failure, handle error */
                    *n = 0;
                    return NULL;
                }
                /* (optional) set all elements in row 0 */
                memset (matrix[found], 0, sizeof *matrix);
                found += 1;                     /* increment found count */
                ndx = next8 = 0;                /* reset ndx, set next8 to count */
            }
        }
        else            /* otherwise, not a match and not counting */
            ndx = 0;    /* set match index to 0 */
    }
    
    *n = found;         /* update value at n to found, so n available in main */
    
    return matrix;      /* return allocated matrix */
}

(note: the number of elements in s is provided in selem and the number of elements in w is provided by welem)

Changing your s[] in main to int s[] = {1,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0} so it is easy to verify the results, you could write you program as:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ARSZ  1000      /* if you need a constant, #define one (or more) */
#define AFTER    8

/* function returning allocated pointer to array of 8 int, *n of them */
int (*sniffer (int *s, int selem, int *w, int welem, int *n))[AFTER]
{
    int ndx = 0,                    /* match index */
        next8 = AFTER,              /* counter for next 8 after match found */
        found = 0,                  /* number of tiems w found in s */
        (*matrix)[AFTER] = NULL;
    
    for (int i = 0; i < selem; i++) {           /* loop over each int in s */
        if (next8 < AFTER) {                    /* count if next8 less than AFTER */
            matrix[found-1][next8++] = s[i];    /* set next8 index in matrix row */
        }
        else if (s[i] == w[ndx]) {              /* if s[i] matches w[ndx] */
            if (++ndx == welem) {               /* increment ndx, compare w/welem */
                /* allocate storage for next row in matrix */
                if (!(matrix = realloc (matrix, (found + 1) * sizeof *matrix))) {
                    perror ("realloc-matrix");  /* on failure, handle error */
                    *n = 0;
                    return NULL;
                }
                /* (optional) set all elements in row 0 */
                memset (matrix[found], 0, sizeof *matrix);
                found += 1;                     /* increment found count */
                ndx = next8 = 0;                /* reset ndx, set next8 to count */
            }
        }
        else            /* otherwise, not a match and not counting */
            ndx = 0;    /* set match index to 0 */
    }
    
    *n = found;         /* update value at n to found, so n available in main */
    
    return matrix;      /* return allocated matrix */
}

int main (void) {
    
    int s[] = {1,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0},
        w[] = {1,0,1},
        n = 0,
        (*result)[AFTER] = NULL;
    
    result = sniffer (s, sizeof s/sizeof *s, w, sizeof w/sizeof *w, &n);
    
    for (int i = 0; i < n; i++) {                       /* loop over result matrix */
        printf ("matrix[%d] = {", i);                   /* output prefix */
        for (int j = 0; j < AFTER; j++)                 /* loop over column values */
            printf (j ? ",%d" : "%d", result[i][j]);    /* output column value  */
        puts ("}");                                     /* output suffix and \n */
    }
    
    free (result);      /* free allocated memory */
}

Example Use/Output

$ ./bin/pattern_in_s
matrix[0] = {0,0,0,0,1,1,1,1}
matrix[1] = {1,1,1,1,0,0,0,0}

If I have misunderstood your question, please let me know in a comment below and I'm happy to help further. Let me know if you have any questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • First I appreciate very much your help ! , really appreciated. you almost understand the question but there's no need for reallocation / dynamic allocation. my problem exactly like this , you search for given @SearchedWord within the array, at each occurrence you store the following 8bit that's appear after each occurrence in a row matrix . every row matrix corresponds to each occurrence. this means at first occurrence you store the following 8bit in the first row of the matrix. if there's second occurrence then you – LiamLony Jan 02 '21 at 12:11
  • store the following 8bit of the second occurrence in the second row of the matrix ...the same process at each occurrence .. so then return the matrix. we conclude that each row of the matrix corresponds to each occurrence correspondingly, in other words first row corresponds to first occurrence, second row corresponds to second occurrence ..etc , hope now is more understandable . at the end we return the matrix as you done above but there's no need for dynamic allocation no? – LiamLony Jan 02 '21 at 12:11
  • Yes, if you want a pointer to within `s` as your matrix, then @MOehm has a fine answer there. I was uncertain how you needed the matrix and did want to "return" a matrix as indicated. Regardless, you now have two ways to approach the problem. As long as `s` won't change, then using a pointer to the element following each occurrence is fine. If `s` may change or go out of scope, then allocating and storing a copy of the next 8 integers is a good option. That's really the only consideration for using one method over the other. – David C. Rankin Jan 02 '21 at 12:14
1

There are several issues you must solve.

How are arrays represented?

You have arrays of integers, whose valid values can be 0 or 1. How do you datermine the length of sich an array. There are basically two possibilities:

  • Use a sentinel value. That's how C strings are stored: The actual string is terminated by the special value '\0', the null terminator. The memory used to store the string may be larger. In your case, you could use a value that isn't used:

    enum {
        END = -1
    };
    
    int a[] = {0, 1, 0, 1, END};
    

    The disadvantage here is that you must be careful not to forget the explicit terminator. Also, if you want to find out the length of an array, you must walk it to the end. (But that's not an issue with small arrays.)

  • Use an explicit length that goes along with the array.

    int a[] = {1, 0, 1, 0};
    int alen = sizeof(a) / sizeof(*a);
    

    The disadvantage here is that you must pass the length to any function that operates on the array. The function f(a) does not know kow long a is; the function should be something like f(a, alen). (The sizeof(a) / sizeof(*a) mechanism works only when the array a is in scope. See here for a discussion on how to find the length of an array.)

    You could, of course, define a struct that combines data and length.

How do you return an array from a function?

That's your actual question. Again there are several possibilities:

  • Return the array. That usually means to allocate the array you want to return on the heap with malloc, which means that the caller must call free on the result at some time. The caller must know how big the returned array is. You can use sentinels as described above or you could pass in a pointer to a sive variable, which the function fills in:

    int **f(..., int *length) { ... }
    

    Call this function like this:

    int length;
    int **p = f(..., &length);
    
    for (int i = 0; i < length; i++) ...
    
  • Pass in an array and hve the function fill it. That means that the function must know about the size of the array. The return value can be used to return the actual size of the array:

    int f(..., int **res, int max) { ... }
    

    Call this function like this:

    int *p[20];
    int length = f(..., p, 20);
    
    for (int i = 0; i < length; i++) ...
    

Let's apply this to your problem.

You want to match a pattern in a string and then return a list of all 8-bit sequences after the matches. Let's represent an array as array + length. Your function might then look like this:

int sniffer(const int *s, int slen,         // haystack array + length
            const int *w, int wlen,         // needle array + length
            const int **res, int reslen)    // results array
{ ... }

It passes in the arrays s and w plus their lengths. It also passes in a third array plus its length. That array hold the results. The number of valid results – the number of rows in your matrix – is the returned value.

Call this function:

int s[] = {...};
int w[] = {...};

const int *res[8];
int n = sniffer(s, sizeof(s) / sizeof(*s),
                w, sizeof(w) / sizeof(*w),
                res, sizeof(res) / sizeof(*res));                    

What happens if there are more than reslen matches? The excess matches cannot be written, of course, but do they contribute to the return value? If they do, you could pass in an array length of 0 just to see how many matches there are. (That' s what the string function snprintf does, in a way.) If they don't you get the exact length of the result array. Both strategies are valid.

Here's an example implementation. It uses your test case #2:

#include <stdlib.h>
#include <stdio.h>

/* 
 *  test whether the next len elements of s and w match
 */
int match(const int *s, const int *w, int len)
{
    while (len-- > 0) {
        if (*s++ != *w++) return 0;
    }
    
    return 1;
}

int sniffer(const int *s, int slen,         // haystack array + length
            const int *w, int wlen,         // needle array + length
            const int **res, int reslen)    // results array
{
    int n = 0;
    
    for (int i = 0; i <= slen - wlen - 8; i++) {
        const int *p = s + i;
    
        if (match(p, w, wlen)) {
            if (n < reslen) res[n] = p + wlen;
            n++;
        }
    }  
  
    return n;
}



int main(void)
{
    int s[] = {1, 1, 0, 0, 1, 1, 1, 1,
               1, 1, 1, 1, 1, 1, 0, 0,
               1, 0, 1, 0, 1, 0, 1, 0};
    int w[] = {1, 1, 0, 0};

    const int *res[8];
    int reslen = sizeof(res) / sizeof(*res);
    
    int n = sniffer(s, sizeof(s) / sizeof(*s),
                    w, sizeof(w) / sizeof(*w),
                    res, reslen);                    

    printf("%d patterns:\n", n);
    for (int i = 0; i < n && i < reslen; i++) {
        printf("[%d] {", i);
        
        for (int j = 0; j < 8; j++) {
            if (j) printf(", ");
            printf("%d", res[i][j]);
        }
        
        printf("}\n");
    }

    return 0;
}
M Oehm
  • 28,726
  • 3
  • 31
  • 42
  • I like it. We have to presume `s` is not changed after the `res` is filled, but given what the question has, that is probably safe. – David C. Rankin Jan 02 '21 at 12:01
  • Thanks. Yes, if the underlying data changes, the pointers are invalidated, but storing a "view" into data is a comon pattern. (I should probably make this decision explicit, but the answer is already quite long.) – M Oehm Jan 02 '21 at 12:20
  • Once you have fihured out what OP really wants, the question is quite interesting and there are many ways to solve it, as you have shown. I see a correlation with string searching functions -- one could, for example, implement a `strtok`-like iterator -- and I wonder if the OP wouldn't be better off to store the binary data as string of `'0'`'s and `'1'`'s. – M Oehm Jan 02 '21 at 12:23
  • @MOehm yes exactly you understood my problem, thanks alot. may you please explain your algorithm? what does match function do? I don't want to cope/paste the code without even understand what's going on. it would be appreciated if you can explain your algorithm of your code by an actual example, thanks alot. – LiamLony Jan 02 '21 at 12:28
  • @MOehm I thought about string method .. the problem the conversion from int to string and then at the end we need to convert from string to int (it's mroe complex) – LiamLony Jan 02 '21 at 12:28
  • The match function returns 1 when `len` elements of `a` and `w` are the same. It's a bit like what you try to do with `found` in your code, but I think it's more convenient to have a separate function, so you can `return 0` early if there is a mismatch. The core algorithm just tests for matches at all possible positions; `p` is a pointer to the sub-array starting at that position. The code really isn't hard to understand; it's basically two nested loops, but in separate functions. – M Oehm Jan 02 '21 at 12:37
  • As for using strings: If you use this representation throughout your program you won't have to convert anything, but you' can use `strstr` to find the next occurrence of `w`. – M Oehm Jan 02 '21 at 12:41
  • Understand ! , appreciated much. – LiamLony Jan 02 '21 at 19:06