reverse-alphabetizing a string in c - c

#include <stdio.h>
#include <string.h>
int main(void)
{
int i, temp;
char input[50];
printf("Enter a string: \n");
scanf("%s", input);
for(i=0; input[i] != '\0'; i++) {
if(strcmp(input[i], input[i+1])<0) {
temp=input[i];
input[i]=input[i+1];
input[i+1]=temp;
}
}
printf("%s\n", input);
return(0);
}
I am supposed to write a program which sorts the characters of a user-inputted string into backwards alphabetical order. I believe I am using the strcmp function incorrectly?

You are comparing chars, you dont need to use strcmp which compares null terminated char arrays.
a simple input[i] == input[i+1] will be OK.
this will compare the ascii codes of the characters.

strcmp is used to compare char arrays not chars themselves, which can be simply compared with >.
That's not the only problem: bubble sort needs 2 loops (O(n**2) complexity) so even with the compare fix, your loop doesn't sort it completely. For instance, enter acbac, one loop will not be enough to move the last c in 2nd position since it only swaps neighbour elements once.
Here's an implementation which does the job, using a double loop (with half of the string in the inner loop) and proper char comparison.
#include <stdio.h>
#include <string.h>
int main(void)
{
int i,j, temp;
char input[50];
printf("Enter a string: \n");
scanf("%49s", input);
for(i=0; input[i] != '\0'; i++) {
for(j=i+1; input[j] != '\0'; j++) {
if (input[i] < input[j]) {
temp=input[i];
input[i]=input[j];
input[j]=temp;
}
}
}
printf("%s\n", input);
return(0);
}

Why not use qsort?
int compareFunction(const void *a, const void *b) {
char char1 = 0[(char *) a];
char char2 = 0[(char *) b];
if (char1 > char2) return -1;
if (char1 == char2) return 0;
if (char1 < char2) return 1;
}
....
qsort(input, strlen(input), 1, compareFunction);

Related

scanf does not work with &str when str is defined as char str[100]

Please, can someone tell me what is the problem in my syntax. I want to find the duplicate letters in a word. it is working properly if I declare a character array here itself but not working with scanf.
#include<stdio.h>
// Finding the duplicate alphabets in a string
int length(char str[]) //Finding the length of the string
{
int len;
while(str[len]!='\0')
{
len++;
}
return len;
}
void duplicate(char str[],int n)
{
int i,j,flag;
for(i=0;i<=n-2;i++) //Selecting the alphabet for comparison
{
flag=0;
if(str[i]!='\0')
{
for(j=i+1;j<=n-1;j++) //comparison of alphabets
{
if(str[j]==str[i])
{
flag=1;
str[j]=0;
}
}
if(flag==1)
{
printf("%c is the duplicate character\n",str[i]);
}
}
}
}
int main()
{
char str[100];
scanf("%s",&str);
int n= length(str);
duplicate(str,n);
}
The problems that I noticed:
main: scanf("%s",&str); is the wrong type for str (char (*)[100]) and should be scanf("%s", str);. char str[100] uses a magic 100 value, instead #define STR_LEN 99 so you can do char str[STR_LEN + 1]. The way you use scanf is subject to buffer overflow instead you should use scanf("%" str(STR_LEN) "s", STR_LEN, str) and you need #define str(s) xstr(s) and #define xstr(s) #s. I suggest using fgets instead.
length: int len; is uninitialized and should be int len = 0; (len is not a great variable name as it's usually 1 bigger than last index, but you use it to index with). Why did you write your own instead of using strlen? As you only return values 0 or great, consider using unsigned instead of int for the type of i and the return value.
duplicate (minor issue): it's good practice to minimize variable scope so for(int i = 0; ... and declare flags where you initilize it. You should technically ensure that n > INT_MIN + 1 for underflow, or change type to an unsigned value, or just calculate it yourself internally.
You can also create an array of counts for each letter. Initialized to 0, and add 1 as you find each letter. Then report the letters with count > 1. This would be a O(n) algorithm instead of the original O(n^2).
#include <limits.h>
#define CHARS (UCHAR_MAX+1)
void duplicate(char *str) {
unsigned char counts[CHARS] = { 0 }; // 0, 1 or 2 for 2+
for(unsigned i=0; str[i]; i++) {
char *c = counts + (unsigned) str[i];
*c += *c <= 1;
}
for(unsigned i=0; i<CHARS; i++) {
if(counts[i] > 1) {
printf("%c is the duplicate character\n", (char) i);
}
}
}
As advised, always ensure that your local variables are initialized before attempting to use them. As for your problem, if your sole desire is to find duplicate strings then you could approach it this way:-
#include<stdio.h>
#define CHAR_SIZE 100
int length(char[]);
void duplicate(char[], int);
// Finding the duplicate alphabets in a string
int length(char str[]) //Finding the length of the string
{
int len = 0;
while(str[len] !='\0')
len++;
return len;
}
//find duplicates
void duplicate(char str[],int n)
{
for(int i =0; i < n; i++)
for(int j=i+1; j<n; j++)
if(str[i] == str[j])
printf("%c is the duplicate character\n",str[i]);
}
//test case
int main()
{
char str[CHAR_SIZE];
puts("Enter string\n");
scanf("%s",str);
int n= length(str);
printf("len of entered str is %d\n\n", n);
duplicate(str,n);
}

How to compare an array to a reversed one and check if their values match?

I wrote a program that reverses an array with the strrev() function and checks if its values matches the original one, sort of a palindrome. When the values match, it prints Palindrome, else, Not a palindrome.
But when I compare them, and the values don't match, it still prints Palindrome.
Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <string.h>
#define MAX_LEN 100
void palindrom(char string[]);
int main()
{
char string[MAX_LEN] = { 0 };
printf("Enter string (max length 100 chars): ");
fgets(string, MAX_LEN, stdin);
if(string[strlen(string)-1] == '\n') { string[strlen(string)-1] = 0; }
palindrom(string);
return (0);
}
void palindrom(char string[])
{
int check = 0;
check = strcmp(strrev(string), string);
if (check == 0)
{
printf("Palindrome");
}
else
{
printf("Not a palindrome");
}
}
What's my problem? Thanks.
From what I can tell strrev may modify the original string as well, so you need to copy it.
The key is strrev.
Here's a program in C that will do what you're testing for:
#include <stdio.h>
#include <string.h>
int main()
{
char a[100], b[100];
printf("Enter the string to check if it is a palindrome\n");
fgets(a, 100, stdin);
strcpy(b,a);
strrev(b);
if (strcmp(a,b) == 0)
printf("Entered string is a palindrome.\n");
else
printf("Entered string is not a palindrome.\n");
return 0;
}
Since others have clarified what the problem is, I would like to point that it would be faster to check if s[0] == s[len-1], s[1] == s[len-2], until half (rounded up) of the string has been checked.
This would require no extra memory, no copy and half as many comparisons.
Something along the lines of:
void palindrom(char string[])
{
int len = strlen(string) - 1;
int i, limit = len/2 + (len % 2);
for (i = 0; i < limit; i++){
if (string[i] != string[len-i]){
printf("Not a palindrome\n");
return;
}
}
printf("Palindrome\n");
}
Your function fails because strrev modifies the string. You effectively always compare the reversed string to itself.
Here is an alternate function that does not modify the string:
void palindrom(const char *str) {
for (size_t i = 0, j = strlen(str); i < j; i++, j--) {
if (str[i] != str[j - 1]) {
printf("Not a palindrome\n");
return;
}
}
printf("Palindrome\n");
}
You don't need to use strrev to test for a palindrome the following function detects a palindrome just fine without using non-standard C functions:
int ispalindrome(char *str, int len)
{
char *p = &str[0];
char *q = &str[len - 1];
do
{
if(p >= q)
{
return 1;
}
} while (*p++ == *q--);
return 0;
}

How to take a string and arrange words in alphabetical order using C

I'm stuck. I've got quite a big programming assignment and most of it looks easy, the part I'm stuck on is splitting a string of text into individual words in an array and then sorting them in alphabetical order.
E.g. if the string contained the following: "I am stuck. Please help me stack exchange" it would save the words in an array and output them in the following order:
am
exchange
help
i
me
please
stack
stuck
Could you guys please help?
EDIT: Here's what I have so far:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[] = "This is a test String, anything else? lol";
char *hhh;
int i;
for(i=0;str[i];i++){
str[i]=tolower(str[i]); //Converts the string to lower case
}
//Breaks the string into separate words based on spaces and some
//punctuation (Anything which signals the end of a word)
hhh = strtok(str," ,.-:;?!");
while(hhh != NULL){
printf("%s \n",hhh);
hhh = strtok(NULL, " ,.-:;?!");
}
}
As you can see I've converted the words into lower case r and I can output them but I have no idea how to sort them in alphabetical order. Looked into bubble sorting and I understand it but I don't understand how to use it to accomplish what I need.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int cmp(const void *a, const void *b){
return strcmp(*(const char **)a, *(const char **)b);
}
int main(){
char str[] = "This is a test String, anything else? lol";
char *word, *words[strlen(str)/2+1];
int i, n;
for(i=0;str[i];i++){
str[i]=tolower(str[i]);
}
i=0;
word = strtok(str, " ,.-:;?!");
while(word != NULL){
words[i++] = word;
word = strtok(NULL, " ,.-:;?!");
}
n = i;
qsort(words, n, sizeof(*words), cmp);
for(i=0; i<n; ++i)
puts(words[i]);
return 0;
}
My code is pretty "manual" meaning that I don't use stuff like strtok or tolower. I manually loop through everything myself. If you don't like that, just replace the corresponding parts with those functions. Here you go:
#include <stdio.h>
#include <string.h>
#define _WLEN 32 // maximum length of each word
#define _NWORDS 256 // maximum number of words in the sentence
void word_swap(char** w1, char** w2);
int main(int argc, const char * argv[]) {
char* sentence = "The quick brown fox jumps over the lazy dog."; // the sentence
char to_ignore[10] = ".,-\"'!?()"; // characters that are ignored
char words[_NWORDS][_WLEN]; // words will be stored here
int i, j, k=0, l=0, word_count, swapped=0; // some variables that will be needed
/* First we loop through the sentence to separate the words */
for (i=0; i<_NWORDS*_WLEN; i++) {
/* If we reach the end of the sentence, finish up the last word with '\0' and quit the loop */
if (*(sentence+i) == '\0') {
words[k][l] = '\0';
word_count = k+1;
break;
}
/* Check if the current character is one that we want to ignore. If so, skip to the next character. */
for (j=0; j<10; j++) {
if (to_ignore[j] == *(sentence+i)) goto END_FOR;
}
/* If the current character is not a space, add it to a word */
if (*(sentence+i) != ' ') {
words[k][l] = *(sentence+i);
l++;
}
/* ... if it is a space, finish the current word with '\0' and move to the next word */
else {
words[k][l] = '\0';
k++;
l=0;
}
END_FOR:;
}
/* Convert everything to lowercase so it's easy to sort the words */
for (i=0; i<word_count; i++) {
for (j=0; j<_WLEN; j++) {
if (words[i][j] == '\0') break;
/* If the letter is uppercase (ASCII codes 65-90) then add 32 to it, which is the lowercase variant */
if (words[i][j] >= 65 && words[i][j] <= 90) words[i][j] += 32;
}
}
/* Bubble sort the words in alphabetical order */
do {
for (i=0; i<word_count-1; i++) {
if (strcmp(words[i], words[i+1]) > 0) {
word_swap(&words[i], &words[i+1]);
swapped = 1;
break;
} else swapped = 0;
}
} while (swapped != 0);
/* Print the words on the screen */
for (i=0; i<word_count; i++) printf("%s\n", words[i]);
}
void word_swap(char** w1, char** w2) {
char tmp[_WLEN];
memcpy(&tmp, w1, _WLEN);
memcpy(w1, w2, _WLEN);
memcpy(w2, &tmp, _WLEN);
}

Palindrome Checker in C

Where should I include toupper() in my code in order to make a palindrome such as Noon or NoOoON to say it is a palindrome rather than saying it is not a palindrome. I can't seem to figure it out. Thanks.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void reverse(char s[]){
int c, i , j;
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
return;
}
int main(){
char a[20];
char b[20];
printf("Enter a string:\n");
gets(a);
strcpy(b,a); // copies string a to b
reverse(a); // reverses string b
if(strcmp(a, b) == 0) { // compares if the original and reverse strings are the same
printf("The string is a Palindrome\n");
}
else {
printf("The string is not a Palindrome\n");
}
return 0;
}
In your case, you can just use _stricmp instead of strcmp.
Another way to approach this is to convert your string to a single case after it is input. eg
for (char *c = a; *c; c++) *c = toupper(*c);
If you want to use toupper() then you should apply it before you make a copy of the string and reverse it.
That is:
int main() {
char a[20];
char b[20];
int i = 0;
printf("Enter a string:\n");
gets(a);
// make the change here
for (i = 0; i < strlen(a); i++) {
a[i] = toupper(a[i]);
}
strcpy(b, a);
If you convert the string to a single case later, then the copy will not be the same as the original, or you'd have to toupper() both.

end of line character is not detected

A simple program, a static string which is used to read the input, then pass it to the function. Just wondering why it can not find the '\0' character using the while(*string!='\0') expression.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int is_palindrome(char *string)
{
int length, mid, end, i;
length=0;
if (string == NULL)
return 0;
while (string[length] != '\0')
{
printf("%c\n", string[length]);
length++;
}
//Not working version
/*
while(*string!='\0')
length++;
*/
end = length - 1;
mid = length / 2;
printf(" end=%d, mid=%d\n", end, mid);
for (i = 0; i < mid; i++) {
if (string[i] != string[end]) {
printf("It's not palindrome\n");
return 0;
}
end--;
}
if (i == mid) {
printf("It's palindrome\n");
return 1;
}
return 0;
}
int main(void)
{
char string[100];
printf("Enter a string to test for the parlindrome\n");
gets(string);
int length = strlen(string);
printf("You entered %s,length is %d\n", string, length);
if (is_palindrome(string))
;
printf("Enter to Quit\n");
char x;
scanf("%c", &x);
return 0;
}
Instead of
while(*string!='\0')
length++;
write
char* p = string;
while( *p++ )
length++;
otherwise the pointer will not move and you become stuck in an infinite loop (if the string is not empty). Use p to avoid changing the original pointer.
Also initialize all variables before using them, good rule of thumb.
Initialize length to 0 before using its value in the while loop.
Or you could use the standard library function strlen().
Also, in the palindrome check, you should probably decrease end at the same you increase i. As it is, you're comparing the characters in the first half each with the same char at the end. This will match strings like "aaaabfa" but not "abcdcba".

Resources