Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I want to compare strings, each character with all other, whether they be in the same position or has an equal number in another position.
I don’t know how to use the compare of strings correctly, I tried with a for and while loop with a count but I don’t know.
My problem is this. For example.
My password is 1234.
My test is 1234.
In this case i have 4 deaths. Because the numbers are in the same position. But in this case.
My password is 1234.
My test is 1243.
I have 2 deaths because 1 and 2 are in correct position but 4 and 3 are in other position but they are in the other string.
In this case i have 2 deaths and 2 injuries.
Sorry for my english not very good . Thanks for help..
strcmp will not give you the number of characters matching in the given strings. Try the below code, It will give number of matching characters in the input strings.
#include <string.h>
int GetMatchingChars (const char *s1, const char *s2)
{
int len1;
int len2;
int count = 0;
int minLen = 0;
char *shortPtr = NULL;
char *longPtr = NULL;
/* First check if the string are equal, return either len, no need to go further */
if (strcmp (s1, s2) == 0) {
return strlen(s1); /* or s2 */
}
len1 = strlen (s1);
len2 = strlen (s2);
minLen = (len1 <= len2)? len1:len2;
shortPtr = (len1 <= len2)? s1:s2;
longPtr = (shortPtr == s1)? s2:s1;
/* Loop through the shorter string */
while (*shortPtr != '\0') {
if (*shortPtr == *longPtr) {
count++;
}
shortPtr++;
longPtr++;
}
return count;
}
int main()
{
char *s1 = "saac";
char *s2 = "sbab";
printf ("Matching len = %d\n", GetMatchingChars (s1,s2));
}
if you have two strings like below:
char *str1="Hai", *str2="Hai";
Use strcmp(str1,str2) for comparing two strings in C
It will return
0 => if str1==str2
>0 => if str1 > str2, which is lexicographically compared
<0 => if str1 < str2
Adding a point to above answer.
no need to use for loop while comparing, as strncmp takes the strings as input.
strncmp delcaration is
int strncmp(const char *s1, const char *s2, size_t n);
Related
Background Information
I was recently approached by a friend who was given a homework problem to develop a searching algorithm. Before anyone asks, I did think of a solution! However, my solution is not what the teacher is asking for...
Anyway, this is an introductory C programming course where the students have been asked to write a search function called ch_search that is supposed to search an array of characters to determine how many times a specific character occurs. The constraints are what I don't understand...
Constraints:
The arguments are: array to search, character to search for, and length of the array being searched.
The function must use a for-loop.
The algorithm must use the strchr function.
Okay, so the first two constraints I can understand... but the 3rd constraint is what really gets me... I was initially thinking that we could just use a for-loop to iterate through the string from the beginning to the end, simply counting each instance of the character. When the student originally described the problem to me, I came up with (although incorrect) the solution:
Proposed Solution
int ch_search(char array_to_search[], char char_to_search_for, int array_size)
{
int count = 0;
for (int i = 0; i < array_size; i++)
{
// count each character instance
if (array_to_search[i] == char_to_search_for)
{
// keep incrementing the count
count++;
}
}
return count;
}
Then I was told that I had to specifically use the character position function (and apparently it has to be strchr and not strrchr so we can't start at the end I guess?)... I just don't see how that wouldn't be overcomplicating this. I don't see how that would help at all, especially counting from the beginning... Even strrchr might make a little more sense to me. Thoughts?
It's true that having the length of the array and having to use a for loop,
the most natural thing to do would be to iterate over every characters of the
source array. But you can also loop over the result of strchr like this:
int ch_search(char haystack[], char needle, int size)
{
int count = 0;
char *found;
for(; (found = strchr(haystack, needle)) != NULL; haystack = found + 1)
count++;
return count;
}
In this case you don't need the size of the array but the assignment doesn't say
that you have to use it. Obviously this solution requires the source to be '\0'-terminated.
I think the teacher wanted you to use strchr to navigate to the next occurrence of the char_to_search_for within a string:
int ch_search(char array_to_search[], char char_to_search_for, int array_size) {
int count = 0;
for (char *ptr = array_to_search ; ptr != &array_to_search[array_size] ; ptr++) {
ptr = strchr(ptr, char_to_search_for);
if (!ptr) {
break; // Character is not found
}
count++;
}
return count;
}
Note that array_to_search must be null-terminated in order to be used together with strchr solution above.
This sounds like your friend was given a trick question. The function gets an array of chars and the length of that array but is required to use strchr() even though that function only works on '\0' terminated strings (and there was not given any guaranty that the array is '\0' terminated).
You might thing that it would be fine to use strchr() on the array anyway and then compare the returned pointer to the given length of the array to check if it went past the end of the array. But there are two problems with that:
If strchr() searches past the end of the array, then you already have Undefined Behavior before getting to the check. The program might have crashed before returning from strchr(), the returned pointer might be some total garbage or you might get a pointer to an address a bit further in memory than the end of the array.
Even if the returned pointer is just to an address a bit further in memory than the end of the array, then there is the problem that comparing two pointers (or subtracting them to find the distance between the pointed addresses) is Undefined Behavior unless they're both pointing to parts of the same memory object (or one position past the end of the object). In this instance it means that checking if the returned pointer is within the bounds of the array is only defined behavior if the returned pointer is within the bounds of the array (or one past the end) making the check a bit useless.
The only solution to that is to make sure that strchr() is working with a '\0' terminated string. For example:
int ch_search(char array_to_search[], char char_to_search_for, int array_size)
{
char *buffer = malloc(array_size + 1);
// Add test here to check if malloc was succesful
strncpy(buffer, array_to_search, array_size);
buffer[array_size] = '\0';
int count = 0;
for (char *i = buffer; (i = strchr(i, char_to_search_for)) != NULL; i++) {
count++;
}
free(buffer);
return count;
}
strchr is a very convenient function to search for a char in a string.
Find and read more about strchr. This is my favorite function ever!
The C library function char *strchr(const char *str, int c) searches for the first occurrence of the character c (an unsigned char) in the string pointed to by the argument str.
Declaration
Following is the declaration for strchr() function.
char *strchr(const char *str, int c)
Parameters
str − This is the C string to be scanned.
c − This is the character to be searched in str.
Return value
Function returns a pointer to the first occurrence of the character c in the string str, or NULL if the character is not found.
Constraints:
1) The arguments are: array to search, character to search for, and
length of the array being searched.
This constrain gives the length of the array to be searched. The given array has to contain '\0' at some point. However the length of search search can be shorter and specified by the search_length.
Following compact solution takes this under account.
int ch_search(char array_to_search[], char char_to_search_for, int search_length)
{
int count = 0;
for(char *p = array_to_search; ;p++)
{
p = strchr(p, char_to_search_for);
if( p != NULL && (p - array_to_search < search_length) )
count++;
else
break;
}
return count;
}
Or equivalent ch_search2:
#include<stdio.h>
#include<string.h>
int ch_search(char array_to_search[], char char_to_search_for, int search_length)
{
int count = 0;
for(char *p = array_to_search; ;p++)
{
p = strchr(p, char_to_search_for);
if( p != NULL && (p - array_to_search < search_length) )
count++;
else
break;
}
return count;
}
// Your original function:
int ch_search1(char array_to_search[], char char_to_search_for, int array_size)
{
int count = 0;
for (int i = 0; i < array_size; i++){
// count each character instance
if (array_to_search[i] == char_to_search_for){
count++; // keep incrementing the count
}
}
return count;
}
int ch_search2(char array_to_search[], char char_to_search_for, int array_size)
{
int count = 0;
char *p = array_to_search;
for(;;)
{
p = strchr(p, char_to_search_for);
if( p != NULL )
{
if (p - array_to_search >= array_size) // we reached beyond
{
break;
}
else
{
count++;
p++;
}
}
else
break; // char not found
}
return count;
}
int main(void)
{
// the arr has to contain '\0' terminator but we can search within the specified length.
char arr[]={'1','1','2','2','1','1','3','3','3','1','4','4', '1','1','!','1','\0','1'};
char arr1[] = "zdxbab";
printf("count %d count %d \n",ch_search(arr , '1', 12),ch_search2(arr , '1', 12));
printf("count %d count %d \n",ch_search(arr1,'b',strlen(arr1)),ch_search2(arr1,'b',strlen(arr1)));
return 0;
}
Output:
count 5 count 5
count 2 count 2
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
Im trying to find the end of a word for example school and at the end of a word put a s on to it.
Here is what I have so far:
for (int i = 0; i < 10; i++) {
plural[i] = orig[i];
if (plural[i] == NULL) {
plural[i] = 's';
plural[i + 1] = '\0';
}
}
Your code may function of the string in orig is less than 10 characters long and NULL is defined as 0.
But note that NULL is used to represent the null pointer, not the null byte at the end of a string. NULL can be defined this way:
#define NULL ((void*)0)
In this case, your code would generate a warning upon compilation.
It is considered good style to write '\0' for the null byte at the end of a string. The null character constant has the same value, 0 with type int, but is more explicit for the purpose of representing the null byte.
You should test if orig[i] is non null instead of iterating to 10:
char orig[] = "world";
char plural[10];
int i;
for (i = 0; orig[i] != '\0'; i++) {
plural[i] = orig[i];
}
plural[i] = 's';
plural[i + 1] = '\0';
You can determine the position of null-terminator ('\0') by the following:
int len;
for(len = 0; cstr[len]; ++len);
This is a possible minimal implementation of strlen which is stands for to determine the length of a char array. In example:
#include <stdio.h>
int main() {
char cstr[10] = "Test";
size_t len;
for(len = 0; cstr[len]; ++len);
if(sizeof(cstr) > len + 1) {
cstr[len++] = 's';
cstr[len] = '\0';
}
printf("%s\n", cstr);
}
Note: As David C. Rankin mentioned in comments, you have to protect the array bounds. Knowing that this is an array, you can read its size with the sizeof operator.
The most important part of this exercise is to insure you learn to protect your array bounds. If you declare an array of char [10], then the longest string it can hold is 9-chars + the nul-byte. If you plan to add a character to the end (e.g. 's'), then that means the original string can be no longer than 8-chars.
If you declare plural as:
char plural[10] = ""; /* note the initialization to all `0` */
then the maximum number of characters that can be held in plural in order to use plural as a string is sizeof plural - 1 chars (*preserving space for the nul-byte). So you can set a max for the length of your string with:
char plural[10] = ""; /* note the initialization to all `0` */
int max = sizeof plural - 1;
Then after you find your original string length, you can validate that there is sufficient room for the nul-byte, e.g.
if (len >= max) { /* validate room for 's' available */
fprintf (stderr, "error: adding 's' will exceed array size.\n");
return 1;
}
Putting all the pieces together in a short example, you could do something similar to the following:
#include <stdio.h>
int main (int argc, char **argv) {
char plural[10] = "", *def = "school";
int len = 0,
max = sizeof plural - 1;
if (argc == 1) { /* if no argument given, copy def to plural */
char *p = def;
for (int i = 0; *p && i < max; i++, len++)
plural[i] = *p++;
}
else /* otherwise copy argv[1] to plural */
len = snprintf (plural, max, "%s", argv[1]);
if (len >= max) { /* validate room for 's' available */
fprintf (stderr, "error: adding 's' will exceed array size.\n");
return 1;
}
plural[len] = 's'; /* add 's' - (nul-terminated via initialization) */
printf ("original : %s\nappended : %s\n", argc > 1 ? argv[1] : def, plural);
return 0;
}
Example Use/Output
$ ./bin/plural
original : school
appended : schools
$ ./bin/plural 12345678
original : 12345678
appended : 12345678s
$ ./bin/plural 123456789
error: adding 's' will exceed array size.
note: if you are more comfortable with array indexes than with pointer arithmetic, you can use the following equivalent statement for the length finding and copy:
if (argc == 1) /* if no argument given, copy def to plural */
for (int i = 0; def[i] && i < max; i++, len++)
plural[i] = def[i];
else /* otherwise copy argv[1] to plural */
len = snprintf (plural, max, "%s", argv[1]);
Look things over. There are many, many different ways to approach this. A normal addition would be to include string.h and use strlen and strcpy or memcpy instead of a loop to find your length or copy characters to plural (note: for long strings memcpy will be more efficient, but for 10 char -- it makes no difference) Let me know if you have any questions.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I need to count how many strings there is in a "string list". Each string ends as usual with a NUL char ('\0'), and the list ends with two NUL chars in succession.
I wrote a function but I keep getting a segmentation fault:
int numStrsInList(const char* strList) {
int count = 0;
int flag = 0;
if(!(*strList))
return -1;
while (flag != 2) {
if (!(*strList)) {
count++;
flag++;
}
else
flag = 0;
strList++;
}
return count;
}
for example:
const char* empty = "\0";
const char* one = "Hell0 \t\n\v\f\rw0r1d\0";
const char* two = "Hello\0 \t\0";
const char* simple = "Hello\0world\0!\0";
the invocation for example:
numStrsInList(empty)
numStrsInList(one)
numStrsInList(two)
numStrsInList(simple)
for this strings the output should be:
0
1
2
3
There are several issues with your code....
int numStrsInList(const char* strList) {
int count = 0;
int flag = 0;
if(!(*strList)) // this is not right, numStrsInList("\0") returns -1 instead of 0
return -1; // did you mean if (!strlist) ??
while (flag != 2) {
if (!(*strList)) { // maybe using this notation if (!strlist[0])
count++; // would help in avoiding the error above
flag++; // c library has strlen() functions
} // that are much faster and will make your code more readable
else
flag = 0;
strList++;
}
return count;
}
}
Compare to, overall length added per request :)
int numStrsInList(const char* strList, int maxlen)
{
// returns the number of strings in a null terminated array of
// contiguous null-terminated strings.
// maxlen is the maximum overall length of the buffer,
// can be 0 to defeat length checking
const char* s;
int result = 0;
if (!strList) return -1;
for (s = strlist;
s > (char*)1 && s[0] != 0;
s = (maxlen) ? (memchr(s, 0, maxlen - (s - strlist)) + 1)
: (s + strlen(s) + 1) )
{
if ((s - strlist) > maxlen) return -1;
++result;
}
return result;
}
Just use standard C function strchr declared in the header <string.h>.
For example
#include <stdio.h>
#include <string.h>
size_t numStrsInList(const char *s)
{
size_t n = 0;
if (!(s[0] == '\0' && s[1] == '\0'))
{
do
{
s = strchr(s, '\0');
++n;
} while (*++s);
}
return n;
}
int main( void )
{
printf("The number of substrings is %zu\n", numStrsInList("\0"));
printf("The number of substrings is %zu\n", numStrsInList("Hell0 \t\n\v\f\rw0r1d\0")) ;
printf("The number of substrings is %zu\n", numStrsInList("Hello\0 \t\0"));
printf("The number of substrings is %zu\n", numStrsInList("Hello\0world\0!\0"));
}
The program output is
The number of substrings is 0
The number of substrings is 1
The number of substrings is 2
The number of substrings is 3
Without using the standard function strchr the function can be implemented the following way
size_t numStrsInList(const char *s)
{
size_t n = 0;
if (!(s[0] == '\0' && s[1] == '\0'))
{
do
{
while (*s) ++s;
++n;
} while (*++s);
}
return n;
}
Take into account that for example this string
"\0A\0"
contains two substrings: "" and "A". While this string "\0" contains neither substring.
As for your code then already this statement
if(!(*strList))
return -1;
does not make sense.
It seems you mean
if(!strList)
return -1;
that is that the pointer strList is not equal to NULL. However by analogy with standard string functions it is better when the caller checks whether the pointer is equal to NULL.
trying to write function that returns 1 if every letter in “word” appears in “s”.
for example:

containsLetters1("this_is_a_long_string","gas") returns 1
containsLetters1("this_is_a_longstring","gaz") returns 0
containsLetters1("hello","p") returns 0
Can't understand why its not right:
#include <stdio.h>
#include <string.h>
#define MAX_STRING 100
int containsLetters1(char *s, char *word)
{
int j,i, flag;
long len;
len=strlen(word);
for (i=0; i<=len; i++) {
flag=0;
for (j=0; j<MAX_STRING; j++) {
if (word==s) {
flag=1;
word++;
s++;
break;
}
s++;
}
if (flag==0) {
break;
}
}
return flag;
}
int main() {
char string1[MAX_STRING] , string2[MAX_STRING] ;
printf("Enter 2 strings for containsLetters1\n");
scanf ("%s %s", string1, string2);
printf("Return value from containsLetters1 is: %d\n",containsLetters1(string1,string2));
return 0;
Try these:
for (i=0; i < len; i++)... (use < instead of <=, since otherwise you would take one additional character);
if (word==s) should be if (*word==*s) (you compare characters stored at the pointed locations, not pointers);
Pointer s advances, but it should get back to the start of the word s, after reaching its end, i.e. s -= len after the for (j=...);
s++ after word++ is not needed, you advance the pointer by the same amount, whether or not you found a match;
flag should be initialized with 1 when declared.
Ah, that should be if(*word == *s) you need to use the indirection operator. Also as hackss said, the flag = 0; must be outside the first for() loop.
Unrelated but probably replace scanf with fgets or use scanf with length specifier For example
scanf("%99s",string1)
Things I can see wrong at first glance:
Your loop goes over MAX_STRING, it only needs to go over the length of s.
Your iteration should cover only the length of the string, but indexes start at 0 and not 1. for (i=0; i<=len; i++) is not correct.
You should also compare the contents of the pointer and not the pointers themselves. if(*word == *s)
The pointer advance logic is incorrect. Maybe treating the pointer as an array could simplify your logic.
Another unrelated point: A different algorithm is to hash the characters of string1 to a map, then check each character of the string2 and see if it is present in the map. If all characters are present then return 1 and when you encounter the first one that is not present then return 0. If you are only limited to using ASCII characters a hashing function is very easy. The longer your ASCII strings are the better the performance of the second approach.
Here is a one-liner solution, in keeping with Henry Spencer's Commandment 7 for C Programmers.
#include <string.h>
/*
* Does l contain every character that appears in r?
*
* Note degenerate cases: true if r is an empty string, even if l is empty.
*/
int contains(const char *l, const char *r)
{
return strspn(r, l) == strlen(r);
}
However, the problem statement is not about characters, but about letters. To solve the problem as literally given in the question, we must remove non-letters from the right string. For instance if r is the word error-prone, and l does not contain a hyphen, then the function returns 0, even if l contains every letter in r.
If we are allowed to modify the string r in place, then what we can do is replace every non-letter in the string with one of the letters that it does contain. (If it contains no letters, then we can just turn it into an empty string.)
void nuke_non_letters(char *r)
{
static const char *alpha =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
while (*r) {
size_t letter_span = strspn(r, alpha);
size_t non_letter_span = strcspn(r + letter_span, alpha);
char replace = (letter_span != 0) ? *r : 0;
memset(r + letter_span, replace, non_letter_span);
r += letter_span + non_letter_span;
}
}
This also brings up another flaw: letters can be upper and lower case. If the right string is A, and the left one contains only a lower-case a, then we have failure.
One way to fix it is to filter the characters of both strings through tolower or toupper.
A third problem is that a letter is more than just the 26 letters of the English alphabet. A modern program should work with wide characters and recognize all Unicode letters as such so that it works in any language.
By the time we deal with all that, we may well surpass the length of some of the other answers.
Extending the idea in Rajiv's answer, you might build the character map incrementally, as in containsLetters2() below.
The containsLetters1() function is a simple brute force implementation using the standard string functions. If there are N characters in the string (haystack) and M in the word (needle), it has a worst-case performance of O(N*M) when the characters of the word being looked for only appear at the very end of the searched string. The strchr(needle, needle[i]) >= &needle[i] test is an optimization if there are likely to be repeated characters in the needle; if there won't be any repeats, it is a pessimization (but it can be removed and the code still works fine).
The containsLetters2() function searches through the string (haystack) at most once and searches through the word (needle) at most once, for a worst case performance of O(N+M).
#include <assert.h>
#include <stdio.h>
#include <string.h>
static int containsLetters1(char const *haystack, char const *needle)
{
for (int i = 0; needle[i] != '\0'; i++)
{
if (strchr(needle, needle[i]) >= &needle[i] &&
strchr(haystack, needle[i]) == 0)
return 0;
}
return 1;
}
static int containsLetters2(char const *haystack, char const *needle)
{
char map[256] = { 0 };
size_t j = 0;
for (int i = 0; needle[i] != '\0'; i++)
{
unsigned char c_needle = needle[i];
if (map[c_needle] == 0)
{
/* We don't know whether needle[i] is in the haystack yet */
unsigned char c_stack;
do
{
c_stack = haystack[j++];
if (c_stack == 0)
return 0;
map[c_stack] = 1;
} while (c_stack != c_needle);
}
}
return 1;
}
int main(void)
{
assert(containsLetters1("this_is_a_long_string","gagahats") == 1);
assert(containsLetters1("this_is_a_longstring","gaz") == 0);
assert(containsLetters1("hello","p") == 0);
assert(containsLetters2("this_is_a_long_string","gagahats") == 1);
assert(containsLetters2("this_is_a_longstring","gaz") == 0);
assert(containsLetters2("hello","p") == 0);
}
Since you can see the entire scope of the testing, this is not anything like thoroughly tested, but I believe it should work fine, regardless of how many repeats there are in the needle.
I want to create an function which splits strings into two sets of characters, character by character, then merges the second set before the first, character by character. For example string "KILOS" (odd # of chars) would split into "KL" "IO" then "S" where the final output would look like "IKOLS".Meaning for every odd case, the last character from original string holds the last place in the new string. The encode function expects s2 to point to a string containing a string that is converted from s1. Any help, hint would be appreciated! Thank you.
***//I HAVE DELETED MY CODE BECAUSE I ACTUAL STUDENTS MIGHT COPY IT, AND GET CAUGHT PLAGIARISING> SORRY>***
The thing is here the code you have written is complicated and simple looping over the string can solve the problem.
void convert (char *s1, char *s2){
size_t len = strlen(s1);
for( size_t i = 0; i < len; i+=2 ){
if(i+1 < len){
s2[i+1] = s1[i];
s2[i] = s1[i+1];
}else{
s2[i] = s1[i];
}
}
s2[len]=0;
}
If you have to use the function like this:-
char s[6]="hello";
char t[6];
convert(s,t);
printf("%s\n",t);
Here ofcourse it is considered that s2 has enough memory to hold the processed string. This has literally nothing more than the copying logic. You are considering two characters each and then swapping them while copying. At last you reach a position when you are accessing an element which has no pair (odd number of elements). Then you simply copy it and move on.
In case you don't know what array subscripting means - let me tell you, s1[i] is same as *(s1+i).
Edit1
Also in your adaptation of my code in the last line you have put *s2 = 0.
It should be
*(s2+len)=0;
Another thing is in your readline code you don't need these two lines. You can do it simply like this:-
int read_line(char *str, int n)
{
int words; int store=0;
while((words=getchar())!='\n')
{
if(store<n)
{
*str++=words;
store++;
}
}
*str=0;
return store;
}
And
void encode(char *s1, char *s2)
{
int len = strlen(s1);
for( int i = 0; i < len; i+=2 ){
if(i+1 < len){
*(s2+i+1) = *(s1+i);
*(s2+i) = *(s1+i+1);
}else{
*(s2+i) = *(s1+i);
}
}
*(s2+len)='\0'; //<---- note this
}