Terminating loops - c

So I have a function that is supposed to find the mode of a set of data input by a user. I believe there is a problem with how I terminate my loops, using the '\0' character, but I'm not sure. Even if that is the problem, I don't know how to fix it. Any advice appreciated.
int mode(int input[]){
int array[70]={0},i=0,j=0,i2=0,j2=0;
while (input[i]!='\0'){
j=input[i];
array[j]=array[j]+1;
i++;
}
while (array[i2]!='\0'){
if (array[i2]>j2){
j2=array[i2];
i2++;
}
else{
i2++;
}
}
return j2;
}

Generally speaking, you will know how many entries are in the user's input, so your mode() function will be better off as int mode(int num, int input[]). Your code assumes that the values in the input array will be in the range 1..69 without checking. It is odd (though technically legitimate) to write '\0' instead of 0. Your second loop stops when it comes across a zero count. It does that immediately because array[0] is never set to anything other than zero.
I'd write the loops as for loops, whether using a 'zero as sentinel' or 'explicit count'.
int mode(int input[])
{
int array[70];
for (int i = 0; input[i] != 0; i++)
{
int value = input[i];
if (value > 0 && value < 70)
array[value]++;
}
int m_value = array[1];
for (int j = 2; j < 70; j++)
{
if (array[j] > m_value)
m_value = array[j];
}
return m_value;
}
The only difference for the counted version that I recommend is changing the termination condition of the first loop from input[i] != 0; to i < num;.

Related

I am trying to make a code that shows how many letters are in a string and im getting an error

the error:
error: relational comparison result unused [-Werror,-Wunused-comparison]
for (int i = 0; (length = strlen(text)); i < length; i++)
~~^~~~~~~~
My code:
for (int i = 0; (length = strlen(text)); i < length; i++)
{
if (isalpha(text[i]))
{
letters++;
}
printf("Letters: %i\n", letters);
return letters;
}
There are 3 sections in the for loop header: initialization, repeat condition, and update. You have 4 sections. It thinks your initialization of length is the condition, and the comparison i < length is the update (i++ is ignored since it's in an extra section).
If you want to initialize two variables, you can do them both in the initialization section, separated by comma.
for (int i = 0, length = strlen(text)); i < length; i++)
You can also just write i < strlen(text) as the condition, without setting a variable. As long as the loop doesn't modify text, most compilers will realize that the length doesn't change, so they'll optimize this to call strlen() just once.
Or you can use the condition text[i] != '\0' to stop when you reach the end, instead of getting the length first.
As #Barmar noted, your for() statement has too many 'sections'. AND you've missed a curly brace marking the end of the for() code block... (Missing, too, is the start of the function... One can only guess...)
Even easier is this:
for (int i = 0; text[i] != '\0'; i++) // This does what strlen() does without a function call
{
if (isalpha(text[i]))
{
letters++;
}
} // brace was missing..
printf("Letters: %i\n", letters);
return letters;
}
Curly braces can sometimes be clutter, and especially when indentation is off can lead to bugs.This code can be made more streamlined leaving out unnecessary braces...
for (int i = 0; text[i] != '\0'; i++)
if (isalpha(text[i]))
letters++;
And, the test again '\0' is often omitted, too...
for (int i = 0; text[i]; i++)
if (isalpha(text[i]))
letters++;
And, sometimes incrementing an index variable can be 'buried' into the last use of that variable
for (int i = 0; text[i]; )
if (isalpha(text[ i++ ]))
letters++;
And, then, C's guarantee of 0 and 1 (false and true) resulting from conditionals can be used to eliminate a slow, branching conditional...
for (int i = 0; text[i]; )
letters += isalpha(text[ i++ ]);
The beauty of the C language.

Is there a way to extract the value of a variable used in a for loop at a certain point (C)?

I would like to know if there's a way for me to get the current value of "j" outside of the foor loop whenever the conditions is true. The variable "totalvalid" will tell me how many times the condition was met but I would also like to know the exact value of j when the condition is true so that I can use it at a later point. So I would want to extract the value of "j" whenever the "totalvalid = totalvalid +1" happens. Sorry if it looks messy. I'm new to coding and still have no idea how to make it cleaner. Thank you.
for(int j = 0; j < stringnumber; j++){
int valid = 0;
if(str[j][10] == '\0'){
for(int k = 0; k < 10; k++){
if(str[j][k] >= 'A' && str[j][k] <= 'Z'){
valid++;
}
}
if (valid == 10){
totalvalid = totalvalid + 1;
}
}
}
It seems that you want an array of numbers from that pass the condition.
My suggestion would be to make an array of ints, where you will keep these numbers.
Before loop:
int *array_of_valid_ints = (int *) calloc(stringnumber, sizeof(int)); // allocate the array
int number_of_valid_ints = 0;
Inside the if statement:
array_of_valid_ints[number_of_valid_ints] = j;
number_of_valid_ints++;
After the loop ends, you can check the good values with:
printf("This are the good ints: ")
for (int i = 0; i < number_of_valid_ints; i++) {
printf("%d ", array_of_valid_ints[i]);
}
printf("\n");
maybe you can define a variable before the loop as int j=0; then use a while loop instead of for.also remember to write j++ in the while loop.this way you can use the value of j outside of the loop too!

Issue with returning an array of type int from function

I have read through a lot of posts giving ways in which you can return an array of type int from a function. I have attempted to follow the approach of dynamically allocating the memory inside of the function using the malloc() function.
In the example code, I am using a function foo which calculates peaks in an array which are greater than a specified value.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* function declaration */
int *foo(int arr[],int size);
int main()
{
int test[] = {1,2,1,4,5,2,7,8,9,1}; //array of test data.
int *p;
p = foo(test,10);
int w;
for(w=0;w<5;w++)
{
printf(" Peak %d\t",p[w]); // This line is giving a non sensible answer.
}
free(p); // free the memory
return 0;
}
int *foo(int arr[],int size) {
int j;
int Peak_min = 3; // Minimum peak height
int *ret = malloc(size * sizeof(*ret));
if(!ret) return 1;
for (j = 0; j < size -1; ++j)
{
if ( (arr[j] < arr[j+1]) && (arr[j+1] > arr[j+2]) && (arr[j+1] > Peak_min))// Peak criteria
{
ret[j] = arr[j+1];
printf(" Peak_No %d",ret[j]); // This line is giving the correct output.
}
}
return ret;
}
The output printed in the function gives 5 and 9, as expected. However, the output when I call the function in int main() gives non-sensible values. I am struggling to find the error with my code, any suggestions on how I can debug/fix this?
Update
I edited the for loop in the fucntion foo to
for (j = 0; j < size -2; ++j)
{
if ( (arr[j] < arr[j+1]) && (arr[j+1] > arr[j+2]) && (arr[j+1] > Peak_min))// Peak criteria
{
ret[j] = arr[j+1];
printf(" Peak_No %d",ret[j]); // This line is giving the correct output.
}
else
{
ret[j] = 0;
}
}
I am now getting the output I wanted.
malloc() returns unitialized memory.
Inside the function, the assignment of ret[j] is conditional. You never know for sure that which or any index element is actually initialized. After returning the pointer, you unconditionally index into the pointer any to read the values which may be very well unitialized.
In case, you are returning the pointer with the same assignment condition, you can at least use calloc() which returns 0-filled memory, so at least, you have a deterministic value. However, this will fail to differentiate between a left-over index element and an element actually having a value of 0. For better precision, you can memset() the malloc()-ed memory to some guard value which indicates that those node values are not assigned.
Also, another quickfix would be, add one else condition which basically helps to unconditionally assign a value to each element.
Seems the loop must be:
int k= 0;
for (j = 0; j < size -2; ++j)
{
if ( (arr[j] < arr[j+1]) && (arr[j+1] > arr[j+2]) && (arr[j+1] > Peak_min))// Peak criteria
{
ret[k++] = arr[j+1];
}
}
ret[k]= 0;
return ret;
}
and in main:
int w= 0;
while (p[w]) printf(" Peak %d\t",p[w++]);
This creates a list of peaks, terminated with a null entry.

Optimising a naive string search in C

As part of a high performance computing course I'm trying to speed up a naive string search in C as much as possible, and I'd like to know if there's anything obvious that could be done that I've missed in my current iteration or if there's a better direction to go in.
Some restrictions are that the pattern must be searched left to right, each character must be checked separately, and it needs to be based on a for loop.
So far I've reduced the time taken for a pattern of 999 As followed by a B in a text of 9,999,999 As followed by a B from ~18 seconds to ~9 seconds, but I'm not sure if it could be faster given the restrictions above.
The current code is:
int match(char** text, int n, char** pattern, int m){
int i, j, last = n-m;
for(i = 0; i <= last; i++){
for(j = 0; j < m; j++){
if((*text)[i+j] != (*pattern)[j]){
break;
}
}
if(j == m){
return i;
}
}
return -1;
}
Where text is the text to be searched, pattern is the pattern to be searched, n is the length of the text, and m is the length of the pattern.
Edit: This is an implementation of the naive string search algorithm. https://en.wikipedia.org/wiki/String_searching_algorithm#Na.C3.AFve_string_search
Edit 2: Code after #RadLexus idea to change from char** to char* (25% faster):
int match(char* text, int n, char* pattern, int m){
int i, j, last = n-m;
for(i = 0; i <= last; i++){
for(j = 0; j < m; j++){
if(text[i+j] != pattern[j]){
break;
}
}
if(j == m){
return i;
}
}
return -1;
}
I got a 10x speedup simply by doing this:
for (int i = 0; i <= last; i++) {
if (memcmp(&text[i], pattern, m) == 0) {
return i;
}
}
Now you may complain that this no longer uses "for" loops and therefore isn't a solution. But memcmp uses loops and you can lift its implementation into your code if you like. As for why it's so much faster, we have a good answer here: Why is memcmp so much faster than a for loop check?
To use only loops, removing the array indexing in favour of pointers will probably provide another speed-up:
int match(char* text, int n, char* pattern, int m){
char *ptext= text, *pend= text+n, *ptext2;
char *ppat, *ppatend;
if (n<m) return -1;
for (; ptext<pend; ptext++) {
ptext2= ptext; ppat= pattern; ppatend= ppat+m;
for (; ppat<ppatend; ppat++, ptext2++) {
if (*ptext2 != *ppat) {
break;
}
}
if (ppat==ppatend) {
return (ptext-text);
}
}
return -1;
}

Identifying palindromes using stacks

I wrote the following code to check whether a string is a palindrome using stacks. I'm not getting the correct output whenever there are two same continuous characters in the string. For example, the code does say exe is a palindrome. But it says ee is not a palindrome.
int is_palindrome(char str[]) {
int j, top = -1;
char stk_item, s[30];
for (j = 0; j < strlen(str); j++)
s[top++] = str[j];
for (j = 0; j < strlen(str); j++) {
stk_item = s[--top];
if (str[j] != stk_item) return 0; // is not a palindrome
}
return 1; // is a palindrome
}
What may be the issue?
You confused the pre-increment and post-increment operators.
In C, x++ means "increment the value of x after this statement" and ++x means "first increment the value of x and then execute the statement."
The following code should work:
int is_palindrome(char str[]) {
int j, top = -1;
char stk_item, s[30];
for (j = 0; j < strlen(str); j++)
s[++top] = str[j];
for (j = 0; j < strlen(str); j++) {
stk_item = s[top--];
if (str[j] != stk_item) return 0;
}
return 1;
}
First of all, stacks work on Last-In First-Out technique. The last thing you insert into a stack is the first thing which gets out of it.
Basically speaking, there are two things you could do onto a stack, which are insert an object into the stack (typically called push) and remove an object from the stack (typically called pop).
In push technique, you assign the lowest available empty index to the object given. And thus it ought to be s[++top] = str[j]. Because you first increase the index and then fill it with an object.
In pop technique, you just reduce the highest filled index by 1. And thus it ought to be stk_item = s[top--]. Because you first say that the removed object is top and then reduce the index.

Resources