Obtain two cluster via bubble sort mechanism - c

I am trying to obtain two cluster from the strings via bubble sort algorithm. Main logic is putting the character strings to left side and the numbers to right side, and the positions can not be changed according to the right to left reading, also i need to use bubble sort for this implementation(!)
For example;
If the string is '503692EC12FATMA' i need to put it FIRSTLY as 'ECFATMA50369212' but the thing i didn't get it how i can use bubble sort to implement this mechanism besides a single if statement ?
I tried somethings but i always sort the character array via bubble sort i can not store the old positions, i need to use just one array and it needs to be implementation of C.
My code example :
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
char st[25],temp;
int l,i,j;
// clrscr();
printf("enter Any Sting\n");
gets(st);
l=strlen(st);
/*Logic Bubble Sort */
for(i=1;i<l;i++)
for(j=0;j<l-i;j++)
if(st[j]>st[j+1])
{
temp=st[j];
st[j]=st[j+1];
st[j+1] =temp;
}
printf("sorted string \n");
printf("%s",st);
getch();
}
But this gives me : '01223569AACEFMT' (!)
After i made the string 'ECFATMA50369212', i will use this string to arrange a cluster left to right A < B and 0 < 1.
to : 'AACEFMT01223569'
Like two functions, first function, use bubble sort to divide numbers and characters, then use this functions returned array to compare it right to left for sorting to create sorted character array.
Any help would be appreciated.

I think that the problem with your code is that you are bubble-sorting the array according to the ASCII values of the characters, in which upper-case letters (as well as lower-case letters) appear after number characters.
What you could do to make you program work is define you own comparison function, in which you would treat number characters (48 <= ASCII code <= 57) and upper-case letter characters (65 <= ASCII code <= 90) differently.

To do this in a single pass requires a differentiation of digits and non-digits. Once you have that, the algorithm can be summed up as:
Always swap if you have digit in the first slot and a non-digit in the second.
Else, only swap if their both digits or both non-digits and then, only if they're out of order (the higher slot is "less than" the lower slot).
Following that, you can do this in a single bubble-run. Its all about proper comparison:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main()
{
char st[25] = "503692EC12FATMA", temp;
size_t len, i;
int swapped = 1;
puts(st);
len = strlen(st);
while (swapped && len--)
{
swapped = 0;
for (i=0; i<len; ++i)
{
int swap = !isdigit((unsigned char)st[i+1]);
if (isdigit((unsigned char)st[i]))
swap = swap || (st[i+1] < st[i]);
else
swap = swap && (st[i+1] < st[i]);
if (swap)
{
temp = st[i];
st[i] = st[i+1];
st[i+1] = temp;
swapped = 1;
}
}
}
puts(st);
}
Output
503692EC12FATMA
AACEFMT01223569
There are other ways to do this obviously. You can even combine all that madness into a single if expression if you're a masochist, (i didn't for clarity). But to accomplish both clustering and cluster-sorting, this is one way to achieve it.

I suppose it is your homework and you actually need some kind of buble-type sort to do clustering first, without actually sorting, here is sample version which "bubbles" letter to the beginning of the string, preserving their relative positions:
l = strlen(st);
for (i = 1; i < l; i++)
if (isAlpha(st[i])) // bubble this letter to the beginning of the string
for (j = (i - 1); (j >= 0) && !isAlpha(st[j]); j--)
swap(&st[j + 1], &st[j]);
printf("sorted string\n%s\n", st);
NOTE: you need following 2 functions before your main:
char isAlpha(char a) {
return (a >= 'A') && (a <= 'Z');
}
void swap(char* a, char *b) {
char t = *a; *a = *b; *b = t;
}

This is not a bubble sort algorithm. What you're trying to do is just a string manipulation that can be done like that:
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
char st[25],temp;
int l,i,j;
// clrscr();
printf("enter Any Sting\n");
gets(st);
int i;
char sorted_st[25];
int str_index = 0;
for (i = 0; i < strlen(l); ++i) {
if((l[i] >= 'a' && l[i] <= 'z') ||
(l[i] >= 'A' && l[i] <= 'Z')) {
sorted_st[str_index++] = l[i];
}
}
for (i = 0; i < strlen(l); ++i) {
if(l[i] >= '0' && l[i] <= '9') {
sorted_st[str_index++] = l[i];
}
}
// add the terminating zero
sorted_st[str_index++] = '\0';
printf("sorted string \n");
printf("%s",st);
getch();
}
ADVICE: It's better your main function to return int. On successful execution should return '0', in other cases error code.
int main() {
/* code */
return 0;
}

Related

Is this syntax array inside array?

Below code snippet from Leetcode. the given exercise is to find the longest substring without repeating characters. I am trying to understand the logic from someone has posted the solution
I have below question is
I have cnt and s are array. is this array inside array cnt[s[j]] and cnt[s[j]]++? how it works, please help to explain. I have tried to visualize the code execution using this
I have tried to understand below line . I tried to visualize the code execution using
#include <stdio.h>
int lengthOfLongestSubstring(char * s)
{
if (s[0] == '\0')
return 0;
if (s[1] == '\0')
return 1;
int i, j, len, max = 0;
int cnt[255] = {0}; // array of counter
//memset(cnt,0,sizeof(cnt));
for (i=0; s[i]!=0; i++)
{
len = 0;
for (j=i; s[j]!=0; j++)
{
if (cnt[s[j]] == 0) /* What does this mean since cnt and s both are array? is this called array inside array ? */
{
printf("iteration %d %c\n",j,s[j]);
cnt[s[j]]++;
len++;
}
else
{ /* if character are not equal */
break;
}
}
if (len > max)
max = len;
}
return max;
}
int main()
{
char string1[] = "abcabcbb";
printf("%d",lengthOfLongestSubstring(string1));
return 0;
}
The syntax a[b[i]] means the value in b[i] references the index from a to read.
So if you have int a[] = { 10, 100, 1000, 10000, 100000}; int b[] = { 3, 2, 1, 0}; then a[b[0]] resolves to a[3] which has the value 10000.
Note that this requires b to only have values that are valid indexes into a.
It's not an array inside an array, it's using one array to get the subscript into another array.
When you see a complex expression you don't understand, split it up into simpler expressions.
cnt[s[j]]++;
is roughly equivalent to
int charcode = s[j];
cnt[charcode]++;
s is a string, so s[j] contains a character code. So this increments the element of cnt corresponding to that character code, and the final result is frequency counts of each character.

CS50 Week 2 Caesar Practice

My code seems to be working properly except at the point when it should print the final output. The problem is to input a string and output an encrypted version. The encryption works by adding an int defined as the key and then adding that value to each character of the ascii values of the inputed string. My issue is that when the cypher text is outputted there are only spaces and no letters or even numbers.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[]) {
int key = atoi(argv[1]);
printf("%i\n", key);
if (argc != 2) {
printf("Usage: ./ceasar key\n");
} else {
string text = get_string("Plaintext: ");
for (int i = 0, len = strlen(text); i < len; i++) {
int cipher = text[i];
int ciphertext = cipher + key;
int ciphermod = ciphertext % 26;
printf("%c", ciphermod);
}
printf("\n");
}
}
You've got a few issues going on here. Please make sure to thoroughly read the assignment before turning to others for assistance.
The assignment requires you to:
Only encode alphabetic characters. Look to the function isalpha() for this.
Encode both uppercase and lowercase characters accurately. Note that, in ASCII, uppercase letters and lowercase letters are separate entities.
Meaning, you must have your code be able to handle both, as they are each handled differently.
Perhaps taking some time to sit and take in the ASCII table may be helpful to you, as it will help you understand what is really happening when you add the key.
Use the correct formula for encoding letters. The i'th ciphered letter ci corresponding to the i'th plaintext letter pi is defined as ci = (pi + k) % 26.
Your code is equivalent to this formula, but it does not account for wrapping, uppercase/lowercase letters, etc. The project specification doesn't just ask you to repeat the formula, it asks you to solve a problem using it. To do so, you must understand it. I explain more, subsequently.
I recommend:
Modifying the text in-place. Currently, you calculate the ciphered text and print it. If you add code for modifying the text where it sits, it'll make ignoring non-alphabetic characters easier.
Modify the formula.
Where 𝚨 is the ASCII character code for the beginning of either the uppercase or lowercase characters, the formula might shake out as follows:
ci = (pi - 𝚨 + k) % 26 + 𝚨
What this modified formula does is first take the ASCII code for Pi and turn it into a number that represents which letter in the alphabet it is, ignoring case. Then, you can add the key(shift the cipher). Using % 26 on this result then makes sure that the result is between 1 and 26—always a letter. Finally, we add back 𝚨 so that the character has a case again.
Here's the modified code with the solution broken down, step by step:
// ...
for (int i = 0, n = strlen(text); i < n; i++) {
if (!isalpha(text[i])) continue;
if (isupper(text[i])) {
// the letter's ASCII code on its own.
int charcode = text[i];
// the letter's index in the alphabet. A = 0, B = 1, etc.
// this is no longer a valid ASCII code.
int alphabet_index = charcode - 'A';
// the letter's index in the alphabet, shifted by the key.
// note, this may shift the letter past the end/beginning of the alphabet.
int shifted_alphabet_index = alphabet_index + key;
// the letter's index in the alphabet, shifted by the key, wrapped around.
// the modulo operator (%) returns the remainder of a division.
// in this instance, the result will always be between 0 and 25,
// meaning it will always be a valid index in the alphabet.
int shifted_index_within_alphabet = shifted_alphabet_index % 26;
// this is the final ASCII code of the letter, after it has been shifted.
// we achieve this by adding back the 'A' offset so that the letter is
// within the range of the correct case of letters.
int final_shifted_charcode = shifted_index_within_alphabet + 'A';
text[i] = final_shifted_charcode;
}
else { // islower
int charcode = text[i];
int alphabet_index = charcode - 'a';
int shifted_alphabet_index = alphabet_index + key;
int shifted_index_within_alphabet = shifted_alphabet_index % 26;
int final_shifted_charcode = shifted_index_within_alphabet + 'a';
text[i] = final_shifted_charcode;
}
}
printf("ciphertext: %s\n", text);
// ...
And here is the solution, simplified down:
// ...
for (int i = 0, n = strlen(text); i < n; i++) {
if (!isalpha(text[i])) // if not alphabetic, skip
continue; //
if (isupper(text[i])) // if uppercase
text[i] = (text[i] - 'A' + key) % 26 + 'A'; //
else // if lowercase
text[i] = (text[i] - 'a' + key) % 26 + 'a'; //
}
printf("ciphertext: %s\n", text);
// ...
Just as a side note, the statement if (!isalpha(text[i])) is acting like something called a guard clause. This is a useful concept to know. Using guard clauses allows you to have simpler, more readable code. Imagine if I had nested all of the code inside the for loop under the if (isalpha(text[i])) condition. It would be harder to read and understand, and difficult to match up the different bracket pairs.
Edit: I would also echo what chqrlie said. Do not use argv[n] until you have verified that argc >= (n + 1)
The formula to compute the ciphered characters is incorrect:
you should only encode letters
you should subtract the code for the first letter 'a' or 'A'
you should add the code for the first letter 'a' or 'A' to the encoded index.
Note also that you should not use argv[1] until you have checked that enough arguments have been passed.
Here is a modified version:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("Usage: ./ceasar key\n");
} else {
int key = atoi(argv[1]);
printf("%i\n", key);
string text = get_string("Plaintext: ");
for (int i = 0, len = strlen(text); i < len; i++) {
int c = text[i];
if (c >= 'a' && c <= 'z') {
int cipher = c - 'a';
int ciphertext = cipher + key;
int ciphermod = ciphertext % 26;
c = 'a' + ciphermod;
} else
if (c >= 'A' && c <= 'Z') {
int cipher = c - 'A';
int ciphertext = cipher + key;
int ciphermod = ciphertext % 26;
c = 'A' + ciphermod;
}
printf("%c", c);
}
printf("\n");
}
return 0;
}

First Not Repeating Character Code

Here is the question:
Write a solution that only iterates over the string once and uses O(1) additional memory, since this is what you would be asked to do during a real interview.
Given a string s, find and return the first instance of a non-repeating character in it. If there is no such character, return '_'.
And here is my code:
char firstNotRepeatingCharacter(char * s) {
int count;
for (int i=0;i<strlen(s);i++){
count=0;
char temp=s[i];
s[i]="_";
char *find= strchr(s,temp);
s[i]=temp;
if (find!=NULL) count++;
else return s[i];
}
if (count!=0) return '_';
}
I dont know what's wrong but when given an input:
s: "abcdefghijklmnopqrstuvwxyziflskecznslkjfabe"
the output is for my code is "g" instead of "d".
I thought the code should have escaped the loop and return "d" soon as "d" was found.
Thx in advance!!!
In your program, problem is in this statement-
s[i]="_";
You are assigning a string to a character type variable s[i]. Change it to -
s[i]='_';
At the bottom of your firstNotRepeatingCharacter() function, the return statement is under the if condition and compiler must be giving a warning for this as the function is supposed to return a char. Moreover, count variable is not needed. You could do something like:
char firstNotRepeatingCharacter(char * s) {
for (int i=0;i<strlen(s);i++){
char temp=s[i];
s[i]='_';
char *find= strchr(s,temp);
s[i]=temp;
if (find==NULL)
return s[i];
}
return '_';
}
But this code is using strchr inside the loop which iterates over the string so, this is not the exact solution of your problem as you have a condition that - the program should iterates over the string once only. You need to reconsider the solution for the problem.
May you use recursion to achieve your goal, something like - iterate the string using recursion and, somehow, identify the repetitive characters and while the stack winding up identify the first instance of a non-repeating character in the string. It's implementation -
#include <stdio.h>
int ascii_arr[256] = {0};
char firstNotRepeatingCharacter(char * s) {
char result = '-';
if (*s == '\0')
return result;
ascii_arr[*s] += 1;
result = firstNotRepeatingCharacter(s+1);
if (ascii_arr[*s] == 1)
result = *s;
return result;
}
int main()
{
char a[] = "abcdefghijklmnopqrstuvwxyziflskecznslkjfabe";
printf ("First non repeating character: %c\n", firstNotRepeatingCharacter(a));
return 0;
}
In the above code, firstNotRepeatingCharacter() function iterates over the string only once using recursion and during winding up of the stack it identifies the first non-repetitive character. I am using a global int array ascii_arr of length 256 to keep the track of non-repetitive character.
Java Solution:
Time Complexity: O(n)
Space Complexity: with constant space as it will only use more 26 elements array to maintain count of chars in the input
Using Java inbuilt utilities : but for inbuilt utilities time complexity is more than O(n)
char solution(String s) {
char[] c = s.toCharArray();
for (int i = 0; i < s.length(); i++) {
if (s.indexOf(c[i]) == s.lastIndexOf(c[i]))
return c[i];
}
return '_';
}
Using simple arrays. O(n)
char solution(String s) {
// maintain count of the chars in a constant space
int[] base = new int[26];
// convert string to char array
char[] input = s.toCharArray();
// linear loop to get count of all
for(int i=0; i< input.length; i++){
int index = input[i] - 'a';
base[index]++;
}
// just find first element in the input that is not repeated.
for(int j=0; j<input.length; j++){
int inputIndex = input[j]-'a';
if(base[inputIndex]==1){
System.out.println(j);
return input[j];
}
}
return '_';
}

C: realloc works on Linux, but not on Windows

this is my first question on Stack Overflow, sorry if it's not well written.
I have a little problem. I wrote a program in C (I'm currently learning C, I am a newbie, my first language, don't say I should've learnt Python, please, because I'm doing just fine with C). So, I wrote this little program. It's an attempt of mine to implement a sorting algorithm (I made the algorithm myself, with no help or documentation, it's very inefficient I think, I was just fooling around, though I don't know whether the algorithm already exists or not). The only sorting algorithm I know is QuickSort.
In any case, here is the final program (has plenty of comments, to help me remember how it works if I'll ever revisit it):
// trying to implement my own sorting algorithm
// it works the following way:
// for an array of n integers, find the largest number,
// take it out of the array by deleting it, store it
// at the very end of the sorted array.
// Repeat until the original array is empty.
// If you need the original array, simply
// make a copy of it before sorting
/***************************************/
// second implementation
// same sorting algorithm
// main difference: the program automatically
// computes the number of numbers the user enters
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int *sort(int *a, int n); // sort: the actual sorting function
char *read_line(char *str,int *num_of_chars); // read_line: reads input in string form
int *create_array(char *str, int n); // create_array: counts the num of integers entered and extracts them
// from the string the read_line function returns, forming an array
int size_of_array_to_be_sorted = 0; // of integers
int main(void)
{
int *array, i, *sorted_array, size = 3;
char *str = malloc(size + 1);
if (str == NULL)
{
printf("\nERROR: malloc failed for str.\nTerminating.\n");
exit(EXIT_FAILURE);
}
printf("Enter the numbers to be sorted: ");
str = read_line(str, &size);
array = create_array(str, size + 1);
sorted_array = sort(array, size_of_array_to_be_sorted);
printf("Sorted: ");
for (i = 0; i < size_of_array_to_be_sorted; i++)
printf("%d ", sorted_array[i]);
printf("\n\n");
return 0;
}
int *sort(int *a, int n)
{
int i, j, *p, *sorted_array, current_max;
sorted_array = malloc(n * (sizeof(int)));
if (sorted_array == NULL)
{
printf("ERROR: malloc failed in sort function.\nTerminating.\n");
exit(EXIT_FAILURE);
}
for (i = n - 1; i >= 0; i--) // repeat algorithm n times
{
current_max = a[0]; // intiliaze current_max with the first number in the array
p = a;
for (j = 0; j < n; j++) // find the largest integer int the array
if (current_max < a[j])
{
current_max = a[j];
p = (a + j); // make p point to the largest value found
}
*p = INT_MIN; // delete the largest value from the array
sorted_array[i] = current_max; // store the largest value at the end of the sorted_array
}
return sorted_array;
}
char *read_line(char *str, int *num_of_chars)
{
int i = 0; // num of chars initially
char ch, *str1 = str;
while ((ch = getchar()) != '\n')
{
str1[i++] = ch;
if (i == *num_of_chars) // gives str the possibility to
{ // dinamically increase size if needed
str1 = realloc(str, (*num_of_chars)++);
if (str1 == NULL)
{
printf("\nERROR: realloc failed in read_line.\nTerminating.\n");
exit(EXIT_FAILURE);
}
}
}
// at the end of the loop, str1 will contain the whole line
// of input, except for the new-line char. '\n' will be stored in ch
str1[i++] = ch;
str1[i] = '\0'; // store the null char at the end of the string
return str1;
}
int *create_array(char *str, int n)
{
int *array, i, j, k, num_of_ints = 0;
for (i = 0; i < n; i++) // computing number of numbers entered
if (str[i] == ' ' || str[i] == '\n')
num_of_ints++;
array = calloc((size_t) num_of_ints, sizeof(int)); // allocacting necessary space for the array
if (array == NULL)
{
printf("\nERROR: calloc failed in create_array.\nTerminating.\n");
exit(EXIT_FAILURE);
}
k = 0;
i = 1; // populating the array
for (j = n - 1; j >= 0; j--)
{
switch (str[j])
{
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
case '9': array[k] += ((str[j] - '0') * i);
i *= 10;
break;
case '-': array[k] = -array[k]; // added to support negative integers
default: i = 1;
if (str[j] == ' ' && (str[j - 1] >= '0' && str[j - 1] <= '9'))
/* only increment k
*right before a new integer
*/
k++;
break;
}
}
// the loop works in this way:
// it reads the str string from the end
// if it finds a digit, it will try to extract it from the
// string and store in array, by adding to one of the elements
// of array the current char - ASCII for '0', so that it actually gets a digit,
// times the position of that digit in the number,
// constructing the number in base 10: units have 1, decimals 10, hundreds 100, and so on
// when it finds a char that's not a digit, it must be a space, so it resets i
// and increments k, to construct a new number in the next element of array
size_of_array_to_be_sorted = num_of_ints;
return array;
}
I've written everything myself, so if you think I use some bad methods or naive approaches or something, please tell me, in order for me to be able to correct them. Anyways, my problem is that I have these 'try to handle errors' if statements, after every call of malloc, calloc or realloc. I have a Linux machine and a Windows one. I wrote the program on the Linux one, which has 4GB of RAM. I wrote it, compiled with gcc, had to change a few things in order to make it work, and it runs flawlessly. I have no problem. I then copied it onto a USB drive and compiled it with mingw on my Windows machine, which has 8GB of RAM. I run it, and if I give it more than 3 2-digit integers, it displays
ERROR: realloc failed in read_line.
Terminating.
At least I know that the 'error handling' if statements work, but why does this happen? It's the same code, the machine has twice as much RAM, with most of it free, and it runs with no problem on Linux.
Does this mean that my code is not portable?
Is it something I don't do right?
Is the algorithm wrong?
Is the program very, very inefficient?
Sorry for the long question.
Thanks if you wanna answer it.
The line in question is:
str1 = realloc(str, (*num_of_chars)++);
where *num_of_chars is the current size of str. Because you are using post-increment, the value passed for the new allocation is the same as the current one, so you haven't made str any bigger, but go ahead and act as if you had.

C upper case to lower case

I am having issue with lower casing my words that are being used as inputs. So my program takes in words and sorts them alphabetically and removes duplicates. But I'd like to change words upper case and lower them to equal to lower case words.
example: Apple changes to apple
my input:
./a.out Orange apple banana Apple banana
my output:
Apple
Orange
apple
banana
Here is what I am trying to achieve
output:
apple
banana
orange
Here is my code
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[]) {
int i, j, k, size;
size = argc -1;
char *key;
char* a[argc-1];
for (i = 2; i < argc; i++) {
key = argv[i];
j = i-1;
while (j >= 1 && strcmp(argv[j], key) > 0) {
argv[j+1] = argv[j];
j--;
}
argv[j+1] = key;
}
if (argc > 1){
for (i = 1; i < argc;){
puts(argv[i]);
while (argv[++i] != NULL && strcmp(argv[i - 1], argv[i] ) == 0)
continue;
}
}
return 0;
}
You have a list of words and you want to output them sorted, and only the unique ones. And you want to do it in a case insensitive fashion.
Get all the strings to the same case.
Sort the list of strings.
Don't output repeats.
C has no built in function to lower case a string, but it does have ones to lower case characters: tolower. So we write a function to lower case a whole string by iterating through it and lower casing each character.
void str_lower(char *str) {
for( ; str[0] != NULL; str++ ) {
str[0] = (char)to_lower(str[0]);
}
}
Then we need to sort. That's handled by the built in qsort function. To use it, you need to write a function that compares two strings and returns just like strcmp. In fact, your comparison function will just be a wrapper around strcmp to make qsort happy.
int compare_strings( const void *_a, const void *_b ) {
/* The arguments come in as void pointers to the strings
and must be cast. Best to do it early. */
const char **a = (const char **)_a;
const char **b = (const char **)_b;
/* Then because they're pointers to strings, they must
be dereferenced before being used as strings. */
return strcmp(*a, *b);
}
In order to handle any data type, the comparison function takes void pointers. They need to be cast back into char pointers. And it's not passed the string (char *) it's passed a pointer to the string (char **), again so it can handle any data type. So a and b need to be dereferenced. That's why strcmp(*a, *b).
Calling qsort means telling it the array you want to sort, the number of items, how big each element is, and the comparison function.
qsort( strings, (size_t)num_strings, sizeof(char*), compare_strings );
Get used to this sort of thing, you'll be using it a lot. It's how you work with generic lists in C.
The final piece is to output only unique strings. Since you have them sorted, you can simply check if the previous string is the same as the current string. The previous string is strings[i-1] BUT be sure not to try to check strings[-1]. There's two ways to handle that. First is to only do the comparison if i < 1.
for( int i = 0; i < num_strings; i++ ) {
if( i < 1 || strcmp( strings[i], strings[i-1] ) != 0 ) {
puts(strings[i]);
}
}
Another way is to always output the first string and then start the loop from the second.
puts( strings[0] );
for( int i = 1; i < num_strings; i++ ) {
if( strcmp( strings[i], strings[i-1] ) != 0 ) {
puts(strings[i]);
}
}
This means some repeated code, but it simplifies the loop logic. This trade-off is worth it, complicated loops mean bugs. I botched the check on the first loop myself by writing if( i > 0 && strcmp ... )`.
You'll notice I'm not working with argv... except I am. strings and num_strings are just a bit of bookkeeping so I didn't always have to remember to start with argv[1] or use argv+1 if I wanted to pass around the array of strings.
char **strings = argv + 1;
int num_strings = argc-1;
This avoids a whole host of off-by-one errors and reduces complexity.
I think you can put the pieces together from there.
There are a set of standard functions for checking and changing the type of characters in ctype.h. The one you are interested in is tolower(). You can #include<ctype.h> and then add a snippet like the following to pre-process your argv before doing the sorting:
for(i = 1; i < argc; i++) {
argv[i][0] = tolower(argv[i][0]);
}
That will only operate on the first character of each word. If you need to normalize the entire word:
for(i = 1; i < argc; i++) {
for(j = 0; argv[i][j]; j++) {
argv[i][j] = tolower(argv[i][j]);
}
}
Silly me, I was able to figure it out after looking at my code realizing that i can do key[0] = tolower(key[0]); which i did before having a pointer point at it.
for (i = 2; i < argc; i++) {
key = argv[i];
key[0] = tolower(key[0]);
j = i-1;
while (j >= 1 && strcmp(argv[j], key) > 0) {
argv[j+1] = argv[j];
j--;
}
argv[j+1] = key;
}
Which lower cases the first letter. And if i wanted to lower case all the letters, i would've have used a for loop. Thank you everyone for your contribution. :)

Resources