C Programming. Comparing an array's contents. - c

I have an array as result of my program's input:
//1.
int i, numberOfOccurances;
for(i = 0; i < numOfOccurrances; i++) {
printf("%d",PrintOccurrances[i]);
}
and as an example output:
121
Now I want to compare this array so that I can print an additional statement, for example:
//2.
if (PrintOccurrances == 121) {
printf("This means blah");
} else if (PrintOccurrances == 232) {
printf("This means something else");
}
//what type of variable should i set and HOW should I set it at point 1?
//what type of string statement should I have at point 2.
Thanks for any assistance.

Make a comparison function and use compound literals at the call site:
#include <stdbool.h>
bool int_arr_cmp_n(int const * a, int const * b, size_t len)
{
while (len--)
if (*a++ != *b++)
return false;
return true;
}
Usage:
if (int_arr_cmp_n(PrintOccurrances, (int[]){1,2,1}, 3)) { /* ... */ }

Related

Substitute characters in a string with their values?

I have a string given (a+b)&(a+c) and I have created a truth table with values of a,b, and c. Now the problem is to evaluate the logic expression by substituting a,b, and c with corresponding values from the truth table. How it can be done in C?
Ex: a=0 b=0 c=0 r=(0+0)&(0+)=0
a=0 b=0 c=1 r=(0+0)&(0+1)=0
and so on
The code itself looks like this
#include <stdio.h>
#include <stdlib.h>
int main()
{
char c,* str, *vars, **result;
int i=0,count=0,j=0;
unsigned long long rows;
str = (char*) malloc(1*sizeof(char));
vars=(char*) malloc(1*sizeof(char));
result=(char**)malloc(1*sizeof(char));
char values[] = {'F', 'T'};
while ((c = getchar()) != EOF)
{
str[i++] = c;
str = (char*) realloc(str, (i+1) * sizeof(char));
if (c >= 'a' && c <= 'z')
{
vars[j++]=c;
vars=(char*) realloc(vars,(j+1)*sizeof(char));
count++;
}
}
rows=1ULL<<(count);
result=(char**)realloc(result,(rows+2)*sizeof(char));
for (i = 0; i < rows+1; i++)
{
result[i]=(char*)malloc(sizeof(char)*(count+1));
for (j = 0; j < count; j++)
{
if(i==0)
result[i][j]=vars[j];
else
result[i][j]=values[(i >> j) & 1];
}
}
result[0][count]='R';
for(i=0;i<rows+1;i++)
{
for(j=0;j<count+1;j++)
{
//do something
}
}
Now the problem is to evaluate the logic expression by substituting a,b, and c with corresponding values from the truth table.
Aside from the issues mentioned in the question's comments, substituting alone won't do the job to evaluate the logic expression. The following function for example substitutes the values while evaluating the expression. (You didn't specify the general syntax of your expressions, so I chose to support combinations of the used operators and lower case variables.)
#include <ctype.h>
#include <string.h>
int indx(char *s, char c) { return strchr(s, c)-s; }
char *gstr, *gvars, *vals; // expression string, variables, value combination
char eval()
{ // evaluate expression "gstr"
char or = 0; // neutral element of +
do
{
char and = 1; // neutral element of &
do
{
char c = *gstr++; // get next token
if (islower(c))
and &= indx("FT", vals[indx(gvars, c)]);
else
if (c == '(')
{ // evaluate subexpression
and &= eval();
c = *gstr++; // get next token
if (c != ')')
printf("error at '%c': expected ')'\n", c), exit(1);
}
else
printf("error at '%c'\n", c), exit(1);
} while (*gstr == '&' && ++gstr);
or |= and;
} while (*gstr == '+' && ++gstr);
return or;
}
It can be called from your main (inserted in your code, hence the inconsistent spacing)
result[0][count]='R';
gvars = vars; // make variable names globally accessible
for (i = 1; i <= rows; ++i)
{
gstr = str, vals = result[i], // globally accessible
result[i][count] = values[eval()];
while (isspace(*gstr)) ++gstr;
if (*gstr)
printf("error at '%c': expected end of input\n", *gstr), exit(1);
}
for(i=0;i<rows+1;i++)
{
for(j=0;j<count+1;j++)
{
putchar(result[i][j]);
}
putchar('\n');
}
(Don't forget to put str[i] = '\0'; after your getchar loop to make a null-terminated string.) Note that due to the given for loop counting, the order of the truth table entries is somewhat unusual in that the row with all variables F comes last.

How to generate a new function in C?

I want a function that could take input a single integer from the user with validation, lets call it input_single_int. Such a function would greatly simplify my code. If a user gives incorrect input, then the function should show error and again prompt the user to fill out the correct input. The problem is the validation part, different inputs require different validation. Even if I send a validation function, how do I send the different parameters required by the validation function through input_single_int?
I want this function to be generic, so that I could use it multiple places. In the code given, if I add a parameter in input_single_int to accomodate input of variable b, I would have to change check_a function also, which I don't want to do. I also don't want to use global variables.
The only way which I could think of achieving this is through a function that could generate another function. Something like this:
func generate_check_b(int a) {
return int check_b(int b) { return (b > 0 && b < a); };
}
Is such a thing possible in C?
#define MM_SHOW 8
#define MM_QUIT 9
int input_single_int(int *var, char msg[], int exit_on_eq, int secondary_check(int val)) {
int inp_status, error, temp;
char skip;
do {
error = 0;
printf("%s", msg);
inp_status = scanf("%d", &temp);
if (inp_status != 1) {
error = 1;
do {
scanf("%c", &skip);
if (exit_on_eq) {
if (skip == 'e') {
system("clear");
return MM_SHOW;
} else if (skip == 'q') {
system("clear");
return MM_QUIT;
}
}
} while (skip != '\n');
}
if (!secondary_check(temp)) {
error = 1;
}
} while (error && printf("Please give a correct input.\n"));
*var = temp;
return 0;
}
int check_a(int a) { return a > 0;}
int check_b(int b, int a) { return (b > 0 && b < a);}
int main() {
int a, b;
char amsg[] = "a should be more than 0: ";
char bmsg[] = "b should be more than 0 and less than a: ";
input_single_int(&a, amsg, 1, check_a);
input_single_int(&b, bmsg, 1, check_b);
return 0;
}
A common idiom is a pair of parameters; a function and an opaque context pointer; so a simple case could be something like:
int check_range(int a, void *p) {
int *range = p;
return a >= range[0] && a < range[1];
}
struct Set { int n; int *vals; };
int check_set(int b, void *p) {
struct Set *s = p;
int i;
for (i = 0; i < s->n && s->vals[i] != b; i++) {}
return i < s->n;
}
If you look at the blocks extension to C supported by clang & gcc, it isn't far different from this, except that it is more sugary and has some really scary side effects.

Attempting to split and store arrays similar to strtok

For an assignment in class, we have been instructed to write a program which takes a string and a delimiter and then takes "words" and stores them in a new array of strings. i.e., the input ("my name is", " ") would return an array with elements "my" "name" "is".
Roughly, what I've attempted is to:
Use a separate helper called number_of_delimeters() to determine the size of the array of strings
Iterate through the initial array to find the number of elements in a given string which would be placed in the array
Allocate storage within my array for each string
Store the elements within the allocated memory
Include directives:
#include <stdlib.h>
#include <stdio.h>
This is the separate helper:
int number_of_delimiters (char* s, int d)
{
int numdelim = 0;
for (int i = 0; s[i] != '\0'; i++)
{
if (s[i] == d)
{
numdelim++;
}
}
return numdelim;
}
`This is the function itself:
char** split_at (char* s, char d)
{
int numdelim = number_of_delimiters(s, d);
int a = 0;
int b = 0;
char** final = (char**)malloc((numdelim+1) * sizeof(char*));
for (int i = 0; i <= numdelim; i++)
{
int sizeofj = 0;
while (s[a] != d)
{
sizeofj++;
a++;
}
final[i] = (char*)malloc(sizeofj);
a++;
int j = 0;
while (j < sizeofj)
{
final[i][j] = s[b];
j++;
b++;
}
b++;
final[i][j+1] = '\0';
}
return final;
}
To print:
void print_string_array(char* a[], unsigned int alen)
{
printf("{");
for (int i = 0; i < alen; i++)
{
if (i == alen - 1)
{
printf("%s", a[i]);
}
else
{
printf("%s ", a[i]);
}
}
printf("}");
}
int main(int argc, char *argv[])
{
print_string_array(split_at("Hi, my name is none.", ' '), 5);
return 0;
}
This currently returns {Hi, my name is none.}
After doing some research, I realized that the purpose of this function is either similar or identical to strtok. However, looking at the source code for this proved to be little help because it included concepts we have not yet used in class.
I know the question is vague, and the code rough to read, but what can you point to as immediately problematic with this approach to the problem?
The program has several problems.
while (s[a] != d) is wrong, there is no delimiter after the last word in the string.
final[i][j+1] = '\0'; is wrong, j+1 is one position too much.
The returned array is unusable, unless you know beforehand how many elements are there.
Just for explanation:
strtok will modify the array you pass in! After
char test[] = "a b c ";
for(char* t = test; strtok(t, " "); t = NULL);
test content will be:
{ 'a', 0, 'b', 0, 'c', 0, 0 }
You get subsequently these pointers to your test array: test + 0, test + 2, test + 4, NULL.
strtok remembers the pointer you pass to it internally (most likely, you saw a static variable in your source code...) so you can (and must) pass NULL the next time you call it (as long as you want to operate on the same source string).
You, in contrast, apparently want to copy the data. Fine, one can do so. But here we get a problem:
char** final = //...
return final;
void print_string_array(char* a[], unsigned int alen)
You just return the array, but you are losing length information!
How do you want to pass the length to your print function then?
char** tokens = split_at(...);
print_string_array(tokens, sizeof(tokens));
will fail, because sizeof(tokens) will always return the size of a pointer on your local system (most likely 8, possibly 4 on older hardware)!
My personal recommendation: create a null terminated array of c strings:
char** final = (char**)malloc((numdelim + 2) * sizeof(char*));
// ^ (!)
// ...
final[numdelim + 1] = NULL;
Then your print function could look like this:
void print_string_array(char* a[]) // no len parameter any more!
{
printf("{");
if(*a)
{
printf("%s", *a); // printing first element without space
for (++a; *a; ++a) // *a: checking, if current pointer is not NULL
{
printf(" %s", *a); // next elements with spaces
}
}
printf("}");
}
No problems with length any more. Actually, this is exactly the same principle C strings use themselves (the terminating null character, remember?).
Additionally, here is a problem in your own code:
while (j < sizeofj)
{
final[i][j] = s[b];
j++; // j will always point behind your string!
b++;
}
b++;
// thus, you need:
final[i][j] = '\0'; // no +1 !
For completeness (this was discovered by n.m. already, see the other answer): If there is no trailing delimiter in your source string,
while (s[a] != d)
will read beyond your input string (which is undefined behaviour and could result in your program crashing). You need to check for the terminating null character, too:
while(s[a] && s[a] != d)
Finally: how do you want to handle subsequent delimiters? Currently, you will insert empty strings into your array? Print out your strings as follows (with two delimiting symbols - I used * and + like birth and death...):
printf("*%s+", *a);
and you will see. Is this intended?
Edit 2: The variant with pointer arithmetic (only):
char** split_at (char* s, char d)
{
int numdelim = 0;
char* t = s; // need a copy
while(*t)
{
numdelim += *t == d;
++t;
}
char** final = (char**)malloc((numdelim + 2) * sizeof(char*));
char** f = final; // pointer to current position within final
t = s; // re-assign t, using s as start pointer for new strings
while(*t) // see above
{
if(*t == d) // delimiter found!
{
// can subtract pointers --
// as long as they point to the same array!!!
char* n = (char*)malloc(t - s + 1); // +1: terminating null
*f++ = n; // store in position pointer and increment it
while(s != t) // copy the string from start to current t
*n++ = *s++;
*n = 0; // terminate the new string
}
++t; // next character...
}
*f = NULL; // and finally terminate the string array
return final;
}
While I've now been shown a more elegant solution, I've found and rectified the issues in my code:
char** split_at (char* s, char d)
{
int numdelim = 0;
int x;
for (x = 0; s[x] != '\0'; x++)
{
if (s[x] == d)
{
numdelim++;
}
}
int a = 0;
int b = 0;
char** final = (char**)malloc((numdelim+1) * sizeof(char*));
for (int i = 0; i <= numdelim; i++)
{
int sizeofj = 0;
while ((s[a] != d) && (a < x))
{
sizeofj++;
a++;
}
final[i] = (char*)malloc(sizeofj);
a++;
int j = 0;
while (j < sizeofj)
{
final[i][j] = s[b];
j++;
b++;
}
final[i][j] = '\0';
b++;
}
return final;
}
I consolidated what I previously had as a helper function, and modified some points where I incorrectly incremented .

Customized sort in the order mentioned {2,3....9,A,B,C,D,1,E,F,0}

I am currently implementing a logic to sort the alphanumerical numbers in the order as mentioned {2,3....9,A,B,C,D,1,E,F,0}. Is there a easy and a possible way to do this? I prefer only C programming.
The request is regarding the sort of the 1st nibble in the PI code of FM RDS stations. As Germany is the only country which supports 2 PI codes(D & 1), the order is maintained in this manner.
Thanks in advance guys.
You should write a function (e.g., int custom_compare(const void *p1, const void *p2); that defines this sorting order. That method will return 1 if p1 comes after p2, 0 if they are 'equal', and -1 if p1 comes before p2.
Then, write your sorting method and call your ordering function instead of comparing using operators. That is, instead of if (a < b), use if (custom_compare(&b, &a)).
Also, I created that function prototype above (specifically using pointers as the parameters) because it would work with the qsort library, which is a quicksort implementation that accepts a custom comparison function.
An Implementation
I decided to quickly do a implementation of what I suggested and a small test example.
#include <stdlib.h>
#include <stdio.h>
int custom_compare(const void *p1, const void *p2) {
char *param1 = (char*)p1;
char *param2 = (char*)p2;
int loc1 = 0;
int loc2 = 0;
char order[17] = "23456789ABCD1EF0";
int i;
for (i=0; i<17; i++) {
if (*param1 == order[i]) { loc1 = i; }
if (*param2 == order[i]) { loc2 = i; }
}
if (loc2 < loc1) {
return 1;
} else if (loc1 < loc2) {
return -1;
} else {
return 0;
}
}
void bubble_sort_string(char *string) {
if (!string || !string[0] || !string[1]) { return; }
int i;
int tail = 0;
char tmp;
while (string[tail]) { tail++; }
while (tail) {
i = 1;
while (i <= tail) {
if (custom_compare(&string[i-1], &string[i]) > 0) {
// swap
tmp = string[i];
string[i] = string[i-1];
string[i-1] = tmp;
}
i++;
}
tail--;
}
}
int main() {
char string[33] = "00FFEE11DDCCBBAA9988776655443322";
printf("old string: %s\n", string);
bubble_sort_string(string);
printf("new_string: %s\n", string);
return 0;
}
Output:
$ ./csort
old string: 00FFEE11DDCCBBAA9988776655443322
new_string: 2233445566778899AABBCCDD11EEFF00
$

Bubble sorting an array with nulls in C

I'm trying to create a bubble sort with nulls in the middle in C.
The code works ok when the array is ordered in a way so the nulls are at the end of the array (hense the "continue" condition works).
My array looks like this: [John,David,NULL,Grace,NULL,NULL]
on which I run this function:
void SortContacts(char * people[]) {
int i,j;
char *tempswap;
for (i=0; i<storage-1; i++) {
for (j=0; j<storage-i-1; j++) {
if (people[j+1]==NULL) {
continue;
}
if (strcmp(people[j],people[j+1]) > 0) {
tempswap = people[j];
people[j] = people[j+1];
people[j+1] = tempswap;
}
}
}
}
When executing with the NULL in the middle of the array the exe crashes.
You cannot strcmp a NULL value. Although you are guarding against a strcmp of people[j+1] being NULL, you don't check people[j].
Try the following (untested), which simply provides a strcmp function which treats a NULL like "".
int
strcmpwithnull(const char *a, const char *b)
{
return strcmp(a?a:"", b?b:"");
}
void SortContacts(char * people[]) {
int i,j;
char *tempswap;
for (i=0; i<storage-1; i++) {
for (j=0; j<storage-i-1; j++) {
if (strcmpwithnull(people[j],people[j+1]) > 0) {
tempswap = people[j];
people[j] = people[j+1];
people[j+1] = tempswap;
}
}
}
}
If you want a NULL to be treated as greater than any other string, then try (again untested):
int
strcmpwithnull(const char *a, const char *b)
{
if (a == b)
return 0; /* handles 2 NULLs and two strings at the same location */
else if (!a)
return 1;
else if (!b)
return -1;
else
return strcmp(a, b);
}
If you want them to be less than any other string (including the empty string), swap the return 1 and return -1.
Here is the problem
if (people[j+1]==NULL)
{
continue;
}
You need to check both j and j+1
Also consider What if you have a NULL in the head of the array ? or you have 2 NULLs one after another
So you need also to check the j not only the j+1
you should also check thejisn't null
You want to end up with the nulls at the right of the array. This can be achieved by making nulls strictly greater than any string. You have to encode this into the comparison function.
int cmp(const char *x, const char *y)
{ if(x == 0) return 1;
if(y == 0) return -1;
return strcmp(x, y);
}

Resources