Trying to find numbers repeated in two arrays - c

I am trying to find all of the numbers that are repeated across two arrays..
For example:
array1[2]: 1,2
array2[2]: 1,5
The number that repeats itself is 1 so we create a new array that will contain 1.
array3[2]: 1
My code is:
int func1(int *str, int *str2)
{
int i,j,temp,c[10];
for(i=0;i<*(str+i);i++){
for(j=0;j<*(str2+j);j++){
if(*(str+i) == *(str+j))
{
temp = *(str+i);
*(str+i) = temp;
temp = *(c+i);
return c[i];
}
}
}
return 0;
}
What is the problem?(logically)
Thanks.

There are multiple problems:
The conditions in the two for loops are odd and probably wrong. They are equivalent to:
for (i = 0; i < str1[i]; i++)
for (j = 0; j < str2[j]; j++)
You should probably specify the sizes of the input arrays in the function interface.
In C, you must make sure you always know the sizes of the arrays.
You should probably specify the output array in the function interface.
Since you will need to know how many values were found in common, you'll need to return that number from the function.
Your choice of the names str1 and str2 is unusual. Not technically wrong, but probably not a good idea. Such names should be reserved for character strings, not arrays of integers.
Your local array c is barely used, and is not used safely.
Your code returns when it finds the first pair of numbers that match, not all possible matches.
The first two lines of the body of the if statement elaborately copies the value in str[i] back to itself via temp.
The third line of the body of the if statement copies an uninitialized value from array c into the variable temp.
The last line of the body of the if then returns that uninitialized value.
This adds up to changes such as:
int func1(int *arr1, int num1, int *arr2, int num2, int *arr3)
{
int k = 0;
for (int i = 0; i < num1; i++)
{
for (int j = 0; j < num2; j++)
{
if (arr1[i] == arr2[j])
arr3[k++] = arr1[i];
}
}
return k;
}
Note that this code assumes that the size of arr3 (the array, not the pointer itself) is as big as the product of num1 and num2. If both arrays contain a list of the same value, then there will be one row in the output array, arr3, for each pair so it could use num1 * num2 rows. This points out that the code does not deal with suppressing duplicates; if you need that (you likely do), then the body of the if statement needs to search through the current values in arr3 to check that the new value is not present. It would be wise to add another parameter, int siz3, to indicate the size of the third array; if you run out of space for values, you could then return -1 as an error indication.
The coded algorithm is quadratic (or, more accurately, proportional to the product num1 * num2). If you know the arrays are sorted on entry, you can reduce it to a linear algorithm (proportional to num1 + num2). With duplicate elimination, it is a little more expensive - it isn't quite as simple as 'cubic'. If you know the input arrays contain unique values (no duplicates), then duplicate elimination is obviously not necessary.

for(i=0;i<*(str+i);i++){
for(j=0;j<*(str2+j);j++){
Are wrong. You are applying '<' condition on an integer to itself and hence loop condition breaks. So, the loop never runs.
And why are you using these redundant statements?
temp = *(str+i);
*(str+i) = temp;
Also, this is wrong
temp = *(c+i);
return c[i];
Try more to correct those statements.If you can't do again, I will provide you a solution

Related

Why is my program not copying the contents of string a to string b? Instead it printing some garbage value

The task is to ask user from which character and till where he wants to create another string.
int main()
{
char a[]="Working with stirng is fun";
printf("%s",a);
int s,e,j=0;
scanf("%d%d",&s,&e);
char b[e-s+2];
for(int i=s-1;i<=e-1;i++){
a[j]=b[i];
j++;
}
a[j]='\0';
printf("%s",b);
}
for eg: if the user enters 4 and 7, the output should be "king".
You appear to be trying to copy a portion of a to b, but in fact are assigning to elements of a.
You have your assignment in the loop backwards. Your a[] variable is the source string and b[] is the destination, but your assignment is a[j]=b[i]; which assigns b[i] to a[j]. This is a Really Good Example, by the way, of why variable names like a and b are bad. Had you used variable names like big_string and sub_string you wouldn't have had this problem. Similarly, names like i and j when you have multiple strings are confusing--big_index and sub_index or some such would be far more clear.
Stylistically, you would do better to keep i and j more closely parallel, instead of declaring and increment i on the for line, and declaring and incrementing j entirely differently:
int i, j;
for (i = s - 1, j = 0 ; i <= e - 1 ; i++, j++)
b[j] = a[i];
b[j] = '\0';
seems much cleaner to me.
Better yet, in my opinion, would be to use a single variable to track the number of chars processed, and use it as an offset to the original string and the index to the substring:
start--; // adjust user's input to start at 0 instead of 1
end--;
int dex;
for (dex = 0 ; dex <= end - start ; dex++)
sub_string[dex] = orig_string[start + dex];
sub_string[dex] = '\0';
(I also changed to more clear variable names, and shifted the correction for indexing from 1 to 0 to the variables instead of doing math inside the loop which just adds confusion).
And finally, the easiest way of all to do this is to use the built-in strncpy() function:
strncpy(sub_string, &orig_string[start], end - start + 1);
Just change the line
a[i] = b[j];
to b[j]=a[i];
and a[i] = '\0';
to b[j]='\0';

Why am I getting this output from printing the contents of an array with only 17 bytes?

I am working through CS50 on edX and have reached the problem where you have to do a checksum for credit card numbers.I am new to programming and even newer to C.
I am collecting the digits in arrays so I can manipulate them.
I have collected every other digit from the original number and multiplied this by two.
When I try to print this collection I get the digits I want initially but then a dash and whole load of other numbers - I have no idea where these are coming from?
// establishing another array to collect the doubled digits of every other digit from the first array
int doubledDigs[16];
int k = 0;
// building that array, ensuring to split any multi digit products and add them idnividually
for (int i = 0; i<= 15; i += 2, k++)
{
int a = collector[i] * 2;
if (a > 9)
{
for (int c=0; c < 2; c++, k++)
{
int b = a % 10;
doubledDigs[k] = b;
a = floor(a / 10);
}
}
doubledDigs[k] = a;
}
// print doubledDigs to check it is working
for (int i = 0; i <= 15; i++)
{
int b = doubledDigs[i];
printf ("%i", b);
}
printf ("\n");
//add all the doubled digits together
int doubledProduct = 0;
for (int i=0; i <= 15; i++)
{
doubledProduct += doubledDigs[i];
}
//print product to check
printf("%i\n", doubledProduct);
So if input 1234567890123 as my card number I get 62810410010620-74895702432659
-748924334
as an output.The first 14 digits are correct and the ones that I want - but where are all these other numbers coming from?
You're getting this output because of one of two things: either you're accessing your collector array out of its bounds, or you're failing to initialize the last few members of that array, resulting in garbage data being accessed.
Your algorithm assumes that collector and doubledDigs have the same number of members, but since your code doesn't include the part where you declare that array, it's unclear if that is true or not.
Assuming they are the same size, if you're filling collector with the input "1234567890123", then you're leaving 3 uninitialized members. In C, if you do not explicitly set the value of a variable or array member, its initial value is equal to whatever happens to be in memory at that particular location. For a signed int, that can be anywhere between 2,147,483,647 and -2,147,483,648.
To guard against this, the first thing you may want to do is zero-initialize your array using int collector[16] = {0};.
That only fixes things in the case that collector and doubledDigs are supposed to be the same size. If it's intended that collector has 14 members and doubledDigs has 16, for instance, you will have to revisit your loop logic. In that example, in the last 2 iterations of the loop, you will attempt access the 15th and 16th members of collector, which don't exist. C will not stop you from doing this, but the result is undefined behavior at best.

What's the point of using linear search with sentinel?

My goal is to understand why adopting linear search with sentinel is preferred than using a standard linear search.
#include <stdio.h>
int linearSearch(int array[], int length) {
int elementToSearch;
printf("Insert the element to be searched: ");
scanf("%d", &elementToSearch);
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
return -1; // The element to be searched is not in the array
}
int main() {
int myArray[] = {2, 4, 9, 2, 9, 10};
int myArrayLength = 6;
linearSearch(myArray, myArrayLength);
return 0;
}
Wikipedia mentions:
Another way to reduce the overhead is to eliminate all checking of the loop index. This can be done by inserting the desired item itself as a sentinel value at the far end of the list.
If I implement linear search with sentinel, I have to
array[length + 1] = elementToSearch;
Though, the loop stops checking the elements of the array once the element to be searched is found. What's the point of using linear search with sentinel?
A standard linear search would go through all the elements checking the array index every time to check when it has reached the last element. Like the way your code does.
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
But, the idea is sentinel search is to keep the element to be searched in the end, and to skip the array index searching, this will reduce one comparison in each iteration.
while(a[i] != element)
i++;
First, lets turn your example into a solution that uses sentinels.
#include <stdio.h>
int linearSearch(int array[], int length, int elementToSearch) {
int i = 0;
array[length] = elementToSearch;
while (array[i] != elementToSearch) {
i++;
}
return i;
}
int main() {
int myArray[] = {2, 4, 9, 2, 9, 10, -1};
int myArrayLength = 6;
int mySearch = 9;
printf("result is %d\n", linearSearch(myArray, myArrayLength, mySearch));
return 0;
}
Notice that the array now has an extra slot at the end to hold the sentinel value. (If we don't do that, the behavior of writing to array[length] is undefined.)
The purpose of the sentinel approach is to reduce the number of tests performed for each loop iteration. Compare:
// Original
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i;
}
}
return -1;
// New
while (array[i] != elementToSearch) {
i++;
}
return i;
In the first version, the code is testing both i and array[i] for each loop iteration. In the second version, i is not tested.
For a large array, the performance difference could be significant.
But what are the downsides?
The result when the value is not found is different; -1 versus length.
We have to make the array bigger to hold the sentinel value. (And if we don't get it right we risk clobbering something on the stack or heap. Ouch!)
The array cannot be read-only. We have to be able to update it.
This won't work if multiple threads are searching the same array for different elements.
Using the sentinel value allows to remove variable i and correspondingly its checking and increasing.
In your linear search the loop looks the following way
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
So variable i is introduced, initialized, compared in each iteration of the loop, increased and used to calculate the next element in the array.
Also the function has in fact three parameters if to pass to the function the searched value
int linearSearch(int array[], int length, int value) {
//...
Using the sentinel value the function can be rewritten the following way
int * linearSearch( int array[], int value )
{
while ( *array != value ) ++array;
return array;
}
And inside the caller you can check whether the array has the value the following way
int *target = linearSearch( array, value );
int index = target == array + size - 1 ? -1 : target - array;
If you add the value to search for, you can reduce one comparison in every loop, so that the running time is reduced.
It may look like for(i = 0;;i++) if(array[i] == elementToSearch) return i;.
If you append the value to search for at the end of the array, when instead of using a for loop with initialization, condition and increment you can a simpler loop like
while (array[i++] != elementToSearch)
;
Then the loop condition is the check for the value you search for, which means less code to execute inside the loop.
The point is that you can convert the for loop into a while/repeat loop. Notice how you are checking i < length each time. If you covert it,
do {
} while (array[i++] != elementToSearch);
Then you don't have to do that extra checking. (in this case, array.length is now one bigger)
Although the sentinel approach seems to shave off a few cycles per iteration in the loop, this approach is not a good idea:
the array must be defined with an extra slot and passing its length as 1 less than the defined length is confusing and error prone;
the array must be modifiable;
if the search function modifies the array to set the sentinel value, this constitutes a side effect that can be confusing and unexpected;
the search function with a sentinel cannot be used for a portion of the array;
the sentinel approach is inherently not thread safe: seaching the same array for 2 different values in 2 different threads would not work whereas searching a constant read only array from multiple threads would be fine;
the benefits are small and only for large arrays. If this search becomes a performance bottleneck, you should probably not use linear scanning. You could sort the array and use a binary search or you could use a hash table.
optimizing compilers for modern CPUs can generate code where both comparisons will be performed in parallel, hence incur no overhead;
As a rule of thumb, a search function should not have side effects. A good example of the Principe of least surprise.

Creating multiple random strings in C

I have written a code which creates multiple random strings. But every time I print it, only the last string is printed multiple times even though different strings are created every time. Can anyone tell me what I'm doing wrong.
static const char alphanum[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz";
char s[5],*b[5] ;
int num =0;
for(int j=0;j<5;j++)
{
*b=(char*)malloc(sizeof(char*)*10);
for (int i = 0; i < 4; ++i)
{
num = rand() % (sizeof(alphanum) - 1);
s[i] = alphanum[num];
}
s[4] = 0;
printf("%s\t",s);
b[j] = s;
}
for(int j=0;j<5;j++)
printf("\n%s",b[j]);
}
Assuming that you've seeded the random number generator with, for instance, srand(time(NULL));, so that it will generate different random number sequences on each run of the program, there is one more flaw in your code:
s is a pointer to an array of characters. With the assignment b[j] = s;, you only assign b[j] the pointer (memory location) of s, but not the contents of s. Since the memory location of s does not change, all entries of b contain the same reference to the same string s, which has been changed multiple times. To copy the current content of s to b[j], use strcpy(), like this.
strcpy(b[j], s);
I think your should read the man 3 rand
In facts you have to "seed" your rand by calling void srand(unsigned int seed); one time in the beggining of your application
First of all, doing e.g. *b is the same as *(b + 0) which is the same as b[0]. That means that when you allocate memory you assign it to the same entry all the time.
Secondly, last in the loop you overwrite the pointer and make b[j] point to s, all the time. So all pointers in b will point to the same s. That's why all your strings seems to be the same.
Thirdly, you don't need to allocate dynamically in the loop, as all strings are of a fixed size. Instead declare b as an array of arrays of characters:
char b[5][5];
Then instead of assigning the pointer, you copy the string into the correct entry in b.
Lastly, and for future reference, don't cast the return of malloc.

What does this C code mean? Arrays and pointer variables

So I am instructed to write a function that uses the following prototype:
double stats(int *array, int size, double *std_dev);
The function should return the average value of the array. The argument std_dev is passed by reference so that the standard deviation of the data in the array can be returned. I assume this to mean that I need to calculate standard deviation as well.
I set about this in the following manner:
double stats(int *array, int size, double *std_dev){
int sum = 0; //declare int to hold sum
int i; //index used in for-loops
for (i = size; i>0; i--){ // for every element(i)
sum += array[i]; //add array element to
}
int mean = sum/size;
for (i = size; i>0; i--){ // for every element(i)
sum += array[i] -mean;
}
return 0;
}
The code compiles; but I'm not quite sure if these lines actually do what I think they do, and I don't have parameters to test with:
sum += array[i]; //add array element to
sum += array[i] -mean;
I know that "array" is a pointer variable, but I'm not exactly sure what it is my code is actually doing, can someone please tell me what these lines actually do? Thanks.
EDIT: I am aware that this code does not completely satisfy my objective, it is a WIP that compiles.
EDIT EDIT: That includes the logical correctness of my program.
when you do this
sum += array[i];
you are iterating through every element of the array - i.e., element at each index and storing the result in the variable sum.
a[i] is the ith element of the array a. It can be thought of as *(a+i).
Similarly in the second loop, you are adding up a[i] - sum to the variable sum. I think you are trying to compute the standard deviation in the second loop in which case you need to sum (a[i] - mean)^2 (i.e, square of difference from the mean) into the variable std_dev and then divide by size.
you have problems in your for:
you will never get to array[0] which is the first element in array
use for(i=0;i<size;i++)as for your question
sum +=array[i]; will put in variable sum the result of sum + array[i]
sum += array[i] -mean; will put in sumthe result of array - mean
BTW I have no idea what are you doing in second for loop (mathematically)
but if you don't want to use previous sum which contain the sum of all the array then you
should to set sum to 0 before you run the second for.
BTW, you returning 0
don't you want to return your average which is return mean; in your case ?
in function prototype it says function should return double
what you've done is int mean = sum/size; is an integer value that will cut the numbers after the "."
you probably want to use double mean = sum/size;
and then to return it as I have mentioned before.

Resources