In my code, I used a tolower function in order to eliminate letters not considering their cases. ( case insensitive) but my problem is that if my first input is "HELLO" and my 2nd is "hi" the ouput would be "ello" in lowercase letters instead of "ELLO". Is there any way to fix this? Should I not use tolower function?
#include <stdio.h>
#include <conio.h>
void main()
{
char s1[20],s2[20];
int i,j;
printf("\nEnter string 1:- ");
gets(s1);
printf("\nEnter the string for matching:- ");
gets(s2);
for(int i = 0; s1[i]; i++)
{
s1[i] = tolower(s1[i]);
}
for(int i = 0; s2[i]; i++)
{
s2[i] = tolower(s2[i]);
}
for (i=0;(i<20&&s1[i]!='\0');i++)
{
for (j=0;(j<20&&s2[j]!='\0');j++)
{
if (s1[i]==s2[j])
s1[i]=' ';
}
}
printf("\nString 1 after deletion process is %s",s1);
printf("\nIts compressed form is ");
for (i=0;(i<20&&s1[i]!='\0');i++)
{
if (s1[i]!=' ')
printf("%c",s1[i]);
}
getch();
}
Write a function
Compare the results of tolower() directly — don’t change the strings themselves
Do not use gets() and scanf("%s") — both have no bounds checking
EDIT: sorry, this function simply compares two strings. It is meant to give you an idea of how to use tolower() effectively, not do your work for you. :-)
#include <iso646.h>
#include <ctype.h>
bool is_equal( const char * a, const char * b )
{
while (*a and *b)
{
if (tolower( *a ) != tolower( *b ))
return false;
++a;
++b;
}
if (*a or *b) return false;
return true;
}
Now you can call the function directly.
if (is_equal( "HELLO", "hello" )) ...
Getting a string input from the user in C is always a pain, but you can use fgets() for that.
char s[100]; // the target string (array)
fgets( s, 100, stdin ); // get max 99 characters with null terminator
char * p = strchr( s, '\n' ); // find the Enter key press
if (p) *p = '\0'; // and remove it
puts( s ); // print the string obtained from user
You can always wrap all the annoying stuff for getting strings into a function.
Is there any way to fix this? Should I not use tolower function?
Instead of changing s1[] to lower case, leave s1[] "as is" and change the compare. Still good to change s2[].
// if (s1[i]==s2[j]) s1[i]=' ';
if (tolower(((unsigned char*)s1)[i]) == s2[j]) s1[i]=' ';
tolower(int ch) is well defined for all int values in the unsigned char range and EOF. Since a char may be negative and string processing is best done as unsigned char, use the cast. Also in the s2[] processing.
Also do not use gets(). Research fgets().
Your code has security vulnerabilities because you're using gets() (if the text input by the user is larger than 19 bytes, you'll have buffer overflows on variables s1 and s2). This function is bugged, it's not fixable and should never be used. Instead use, for example, fgets(s1, sizeof(s1), stdin).
The main idea of the problem is that you must preserve the strings, so remove the loops that modify them. In this case the correct predicate for checking if each compared character is the same without regard to case would become:
if (tolower((unsigned char)s1[i]) == tolower((unsigned char)s2[j]))
Related
How should I return an empty string from a function? I tried using lcp[i] = ' ' but it creates an error. Then I used lcp[i] = 0 and it returned an empty string. However, I do not know if it's right.
Also, is it necessary to use free(lcp) in the caller function? Since I could not free and return at the same time.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 50
char *find_LCP(char str1[], char str2[]);
char *find_LCP(char str1[], char str2[]){
char * lcp = malloc(MAX_LEN * sizeof(char));
int a = strlen(str1);
int b = strlen(str2);
int min = a < b ? a : b;
for(int i = 0; i < min; i++){
if(str1[i] == str2[i])
lcp[i] = str1[i];
else
lcp[i] = 0;
}
return lcp;
}
int main()
{
char str1[MAX_LEN], str2[MAX_LEN];
char * lcp;
printf("Enter first word > ");
scanf("%s", str1);
printf("Enter second word > ");
scanf("%s", str2);
lcp = find_LCP(str1, str2);
printf("\nLongest common prefix: '%s'\n", lcp);
free(lcp);
return 0;
}
An "empty" string is just a string with the first byte zero, so you can write:
s[0] = 0;
However, it is not clear what you are trying to do. The LCP of "foo" and "fob" is "fo", not the empty string.
You can also return as soon as you find the first non-matching character, no need to go until the end.
Further, you can simply pass the output string as a parameter and have lcp be an array. That way you avoid both malloc and free:
char lcp[MAX_LEN];
...
find_LCP(lcp, str1, str2);
If you want to empty a string without using a for loop then you can do
lcp[0] = 0
but for emptying a string it was right the way you did using a for loop.
There are plenty other ways of emptying the string word by word using for loop:
lcp[i] = '\0';
and it's the right way to make string empty as letter by letter you trying to do using for loop
But if you are not using some loops and simply empty a string then you can do this.
memset(buffer,0,strlen(buffer));
but this will only work for zeroing up to the first NULL character.
If the string is a static array, you can use:
memset(buffer,0,sizeof(buffer));
Your program has a bug: If you supply two identical strings, lcp[i] = 0; never executes which means that your function will return a string which is not NUL-terminated. This will cause undefined behvaior when you use that string in your printf in main.
The fix for this is easy, NUL-terminate the string after the loop:
int i;
for (i = 0; i < min; i++){
if(str1[i] == str2[i])
lcp[i] = str1[i];
else
break;
}
lcp[i] = 0;
As for the answer to the question, an empty string is one which has the NUL-terminator right at the start. We've already handled that as we've NUL-terminated the string outside the loop.
Also, is it necessary to use free(lcp) in the caller function?
In this case, it is not required as the allocated memory will get freed when the program exits, but I'd recommend keeping it because it is good practice.
As the comments say, you can use calloc instead of malloc which fills the allocated memory with zeros so you don't have to worry about NUL-terminating.
In the spirit of code golf. No need to calculate string lengths. Pick any string and iterate through it until the current character either null or differs from the corresponding character in the other string. Store the index, then copy appropriate number of bytes.
char *getlcp(const char *s1, const char *s2) {
int i = 0;
while (s1[i] == s2[i] && s1[i] != '\0') ++i;
char *lcp = calloc((i + 1), sizeof(*lcp));
memcpy(lcp, s1, i);
return lcp;
}
P.S. If you don't care about preserving one of input strings then you can simplify the code even further and just return the index (the position of the last character of the common prefix) from the function, then put '\0' at that index into one of the strings.
In an effort of solving a textbook problem, I'm trying to create a case insensitive version of the function called strstr() which is in the C language. So far, I've run into two problems. The first problem being that when I make the case insensitive version of strstr() it worked, but it didn't stop at the first matching string and continued to return the string even if they didn't match.
strstr() is supposed to see the first instance of a matching character up to n counts specified and then stop. Like if I wrote: "Xehanort" in string A and "Xemnas" in string B and specified 4, as the number, it would return Xe.
The idea behind the case insensitive version is that I can write : "Xehanort" in one string and "xemnas" in the next string and have it return Xe.
However, I've run into a new problem in new code I've tried: the function doesn't seem to want to run at all. I've tested this and it turns out the function seems to be at a crash and I'm not sure how to make it stop.
I've tried editing the code, I've tried using different for loops but figured that the code doesn't need to be too sophisticated yet, I've also tried different code entirely than what you are going to read, but that resulted in the problem mentioned earlier.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define MAX 100
char *stristr4(const char *p1, const char *p2, size_t num);
int main() {
char c[MAX], d[MAX];
printf("Please enter the string you want to compare.");
gets(c);
printf("Please enter the next string you want to compare.");
gets(d);
printf("The first string to be obtained from \n%s, and \n%s is \n%s",
c, d, stristr4(c, d, MAX));
}
char *stristr4(const char *p1, const char *p2, size_t num) {
const char *str1 = p1;
const char *str2 = p2;
char *str3;
int counter = 0;
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
if (tolower(str1[i]) == tolower(str2[j])) {
str3[i] = str1[i];
counter++;
} else {
if (counter > 0) {
break;
} else
continue;
}
}
}
return str3;
}
The code you see will ask for the strings you want to input. Ideally, it should return the input.
Then it should do the stristr function and return the first instance of matching string with case insensitivity.
However, the function I've created doesn't even seem to run.
Your code has undefined behavior (in this case causing a segmentation fault), because you try to store the resulting string via an uninitialized pointer str3.
Standard function strstr returns a pointer to the matching subsequence, you should do the same. The third argument is useless if the first and second arguments are proper C strings.
Here is a modified version:
char *stristr4(const char *p1, const char *p2) {
for (;; p1++) {
for (size_t i = 0;; i++) {
if (p2[i] == '\0')
return (char *)p1;
if (tolower((unsigned char)p1[i]) != tolower((unsigned char)p2[i]))
break;
}
if (*p1 == '\0')
return NULL;
}
}
Notes:
function tolower() as other functions from <ctype.h> takes an int argument that must have the value of an unsigned char or the special negative value EOF. char arguments must be converted to unsigned char to avoid undefined behavior for negative char values. char can be signed or unsigned by default depending on the platform and the compilers settings.
you should never use gets(). This function is obsolete and cannot be used safely with uncontrolled input. Use fgets() and strip the trailing newline:
if (fgets(c, sizeof c, stdin)) {
c[strcspn(c, "\n")] = '\0'; // strip the trailing newline if any
...
}
A third string could be passed to the function and fill that string with the matching characters.
Use fgets instead of gets.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define MAX 100
int stristr4(const char* p1, const char *p2, char *same);
int main( void)
{
int comp = 0;
char c[MAX] = "", d[MAX] = "", match[MAX] = "";//initialize to all zero
printf ( "Please enter the string you want to compare. ");
fflush ( stdout);//printf has no newline so make sure it prints
fgets ( c, MAX, stdin);
c[strcspn ( c, "\n")] = 0;//remove newline
printf ( "Please enter the next string you want to compare. ");
fflush ( stdout);//printf has no newline so make sure it prints
fgets ( d, MAX, stdin);
d[strcspn ( d, "\n")] = 0;//remove newline
comp = stristr4 ( c, d, match);
printf ( "Comparison of \n%s, and \n%s is \n%d\n", c, d, comp);
if ( *match) {
printf ( "The matching string to be obtained from \n%s, and \n%s is \n%s\n"
, c, d, match);
}
return 0;
}
int stristr4 ( const char *p1,const char *p2, char *same)
{
//pointers not pointing to zero and tolower values are equal
while ( *p1 && *p2 && tolower ( (unsigned char)*p1) == tolower ( (unsigned char)*p2))
{
*same = tolower ( (unsigned char)*p1);//count same characters
same++;//increment to next character
*same = 0;//zero terminate
p1++;
p2++;
}
return *p1 - *p2;//return difference
}
Why can't I print the alphabet using this code?
void ft_putchar(char c)
{
write(1, &c, 1);
}
int print_alf(char *str)
{
int i;
i = 0;
while (str[i])
{
if (i >= 'A' && i <= 'Z')
ft_putchar(str[i]);
else
ft_putchar('\n');
i++;
}
return (str);
}
int main ()
{
char a[26];
printf("%s", print_alf(a));
return (0);
}
I get this warning
format ' %s ' expects type 'char*' but argument 2 has type 'int'
How do I print the alphabet using a string, and write function?
Your entire print_alf function looks suspicious.
You are returning str which is of type char *. Therefore the return type of print_alf should to be char * instead of int.
Your while (str[i]) loop makes no sense at all since you are passing uninitialized memory to it. So your code will very likely corrupt the memory since the while loop will continue to run until a '\0' is found within the memory which does not need to be the case within the boundaries of the passed memory (a).
You are not adding a zero termination character ('\0') at the end of the string. This will result in printf("%s", print_alf(a)); printing as many characters beginning at the address of a until a '\0' is found within the memory.
Here is a suggestion how to fix all that problems:
char *print_alf(char *str, size_t len)
{
char letter;
if ((str) && (len >= 27)) // is str a valid pointer and length is big enough?
{
for (letter = 'A'; letter <= 'Z'; letter++) // iterate all characters of the alphabet
{
*str = letter;
str++;
}
*str = '\0'; // add zero termination!!!
}
else
{
str = NULL; // indicate an error!
}
return (str);
}
int main()
{
char a[26 + 1]; // ensure '\0' fits into buffer!
printf("%s", print_alf(a, sizeof(a)));
return (0);
}
Make up your mind whether print_alf should return a string which you then print with printf or whether print_alf should be a void function that does the printing, which you should then just call without printf. At the moment, your code tries to be a mixture of both.
The easiest way is to just print the alphabet:
void print_alf(void)
{
int c;
for (c = 'A'; c <= 'Z'; c++) putchar(c);
}
Call this function like so:
print_alf(); // print whole alphabet to terminal
A more complicated variant is to fill a string with the alphabet and then print that string. That's what you tried to achieve, I think. In that case, you must pass a sufficiently big buffer to the function and return it. Note that if you want to use the string functions and features of the standard lib (of which printf("%s", ...) is one) you must null-terminate your string.
char *fill_alf(chat *str)
{
int i;
for (i = 0; i < 26; i++) str[] = 'A' + i;
str[26] = '\0';
return str;
}
It is okay to return the buffer that was passed into the function, but beware of cases where you return local character buffers, which will lead to undefined behaviour.
You can call it as you intended in your original code, but note that you must make your buffer at least 27 characters big to hold the 26 letters and the null terminator:
char a[27];
printf("%s\n", fill_alf(a));
Alternatively, you could do the filling and printing in twp separate steps:
char a[27];
fill_alf(a); // ignore return value, because it's 'a'
printf("%s\n", a); // print filled buffer
If you just want to print the alphabet, the print_alf variant is much simpler and straightforward. If you want to operate further on the alphabet, eg do a shuffle, consider using fill_alf.
Your print_alf(char *str) function actually returns an integer which causes the error (it is defined to return int). When you specify %s to printf it expects characters, not numbers.
You can fix this by changing the return type of your function to char and if everything else works in your code you'll be good to go.
Is there any efficient (- in terms of performance) way for printing some arbitrary string, but only until the first new line character in it (excluding the new line character) ?
Example:
char *string = "Hello\nWorld\n";
printf(foo(string + 6));
Output:
World
If you are concerned about performance this might help (untested code):
void MyPrint(const char *str)
{
int len = strlen(str) + 1;
char *temp = alloca(len);
int i;
for (i = 0; i < len; i++)
{
char ch = str[i];
if (ch == '\n')
break;
temp[i] = ch;
}
temp[i] = 0;
puts(temp);
}
strlen is fast, alloca is fast, copying the string up to the first \n is fast, puts is faster than printf but is is most likely far slower than all three operations mentioned before together.
size_t writetodelim(char const *in, int delim)
{
char *end = strchr(in, delim);
if (!end)
return 0;
return fwrite(in, 1, end - in, stdout);
}
This can be generalized somewhat (pass the FILE* to the function), but it's already flexible enough to terminate the output on any chosen delimiter, including '\n'.
Warning: Do not use printf without format specifier to print a variable string (or from a variable pointer). Use puts instead or "%s", string.
C strings are terminated by '\0' (NUL), not by newline. So, the functions print until the NUL terminator.
You can, however, use your own loop with putchar. If that is any performance penalty is to be tested. Normally printf does much the same in the library and might be even slower, as it has to care for more additional constraints, so your own loop might very well be even faster.
for ( char *sp = string + 6 ; *sp != '\0'; sp++ ) {
if ( *sp == '\n' ) break; // newline will not be printed
putchar(*sp);
}
(Move the if-line to the end of the loop if you want newline to be printed.)
An alternative would be to limit the length of the string to print, but that would require finding the next newline before calling printf.
I don't know if it is fast enough, but there is a way to build a string containing the source string up to a new line character only involving one standard function.
char *string = "Hello\nWorld\nI love C"; // Example of your string
static char newstr [256]; // String large enough to contain the result string, fulled with \0s or NULL-terimated
sscanf(string + 6, "%s", newstr); // sscanf will ignore whitespaces
sprintf(newstr); // printing the string
I guess there is no more efficient way than simply looping over your string until you find the first \n in it. As Olaf mentioned it, a string in C ends with a terminating \0 so if you want to use printf to print the string you need to make sure it contains the terminating \0 or yu could use putchar to print the string character by character.
If you want to provide a function creating a string up to the first found new line you could do something like that:
#include <stdio.h>
#include <string.h>
#define MAX 256
void foo(const char* string, char *ret)
{
int len = (strlen(string) < MAX) ? (int) strlen(string) : MAX;
int i = 0;
for (i = 0; i < len - 1; i++)
{
if (string[i] == '\n') break;
ret[i] = string[i];
}
ret[i + 1] = '\0';
}
int main()
{
const char* string = "Hello\nWorld\n";
char ret[MAX];
foo(string, ret);
printf("%s\n", ret);
foo(string+6, ret);
printf("%s\n", ret);
}
This will print
Hello
World
Another fast way (if the new line character is truly unwanted)
Simply:
*strchr(string, '\n') = '\0';
I am using Linux and there is a custom function of which returns an ASCII int of current key sort of like getch(). When trying to get used to it and how to store the password I came into an issue, my code is as follows:
int main() {
int c;
char pass[20] = "";
printf("Enter password: ");
while(c != (int)'\n') {
c = mygetch();
strcat(pass, (char)c);
printf("*");
}
printf("\nPass: %s\n", pass);
return 0;
}
Unfortunately I get the warning from GCC:
pass.c:26: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast
/usr/include/string.h:136: note: expected ‘const char * __restrict__’ but argument is of type ‘char’
I tried using pointers instead of a char array for pass, but the second I type a letter it segfaults. The function works on its own but not in the loop, atleast not like getch() would on a Windows system.
What can you see is wrong with my example? I am enjoying learning this.
EDIT: Thanks to the answers I came up with the following silly code:
int c;
int i = 0;
char pass[PASS_SIZE] = "";
printf("Enter password: ");
while(c != LINEFEED && strlen(pass) != (PASS_SIZE - 1)) {
c = mygetch();
if(c == BACKSPACE) {
//ensure cannot backspace past prompt
if(i != 0) {
//simulate backspace by replacing with space
printf("\b \b");
//get rid of last character
pass[i-1] = 0; i--;
}
} else {
//passed a character
pass[i] = (char)c; i++;
printf("*");
}
}
pass[i] = '\0';
printf("\nPass: %s\n", pass);
The problem is that strcat expects a char * as its second argument (it concatenates two strings). You don't have two strings, you have one string and one char.
If you want to add c to the end of pass, just keep an int i that stores the current size of pass and then do something like
pass[i] = (char) c.
Make sure to null-terminate pass when you are done (by setting the last position to 0).
A single character is not the same as a string containing a single character.
In other words, 'a' and "a" are very different things.
A string, in C, is a null-terminated array of chars. Your "pass" is an array of 20 chars - a block of memory containing space for 20 chars.
The function mygetch() returns a char.
What you need to do is to insert c into one of the spaces.
Instead of "strcat(pass, c)", you want to do "pass[i] = c", where i starts at zero, and increments by one for every time you call mygetch().
Then you need to do a pass[i] = '\0', when the loop is done, with i equal to the number of times you called mygetch(), to add the null terminator.
You're other problem is that you haven't set a value for c, the first time you check to see if it's '\n'. You want to call mygetch() before you do the comparison:
int i = 0;
for (;;)
{
c = mygetch();
if (c == '\n')
break;
c = mygetch();
pass[i++] = c;
}
pass[i] = '\0';
Over and above the correctly diagnosed issue with strcat() taking two strings -- why did you ignore the compiler warnings, or if there were no warnings, why don't you have warnings turned on? As I was saying, over and above that problem, you also need to consider what happens if you get EOF, and you also need to worry about the initial value of 'c' (which could accidentally be '\n' though it probably isn't).
That leads to code like this:
int c;
char pass[20] = "";
char *end = pass + sizeof(pass) - 1;
char *dst = pass;
while ((c = getchar()) != EOF && c != '\n' && dst < end)
*dst++ = c;
*dst = '\0'; // Ensure null termination
I switched from 'mygetch()' to 'getchar()' - primarily because what I say applies to that and might not apply to your 'mygetch()' function; we don't have a specification of what that function does on EOF.
Alternatively, if you must use strcat(), you still need to keep a track on the length of the string, but you can do:
char c[2] = "";
char pass[20] = "";
char *end = pass + sizeof(pass) - 1;
char *dst = pass;
while (c[0] != '\n' && dst < end)
{
c[0] = mygetch();
strcat(dst, c);
dst++;
}
Not as elegant as all that - using strcat() in context is overkill. You could, I suppose, do simple counting and repeatedly use strcat(pass, c), but that has quadratic behaviour as strcat() has to skip of 0, 1, 2, 3, ... characters on the subsequent iterations. By contrast, the solution where dst points to the NUL at the end of the string means that strcat() doesn't have to skip anything. With a fixed size addition of 1 character, though, you're probably better off with the first loop.