word sorting in a string - c

I'm trying to make a function that gets a string and a number from the user and then makes every words length the same as the number i got form the user and prints the new string.
for example :
abcd__efgh_i
number = 3
and i should get
abc_def_ghi
#include < stdio.h >
void f(char * p, int n) {
int i = 0, br = 0, d, m = 0, br1 = 0, g;
while (p[i] != '\0') {
if (p[i] != '\0') {
br++;
}
i++;
}
if (br % n == 0) {
d = (br / n) - 1;
} else {
d = (br / n);
}
g = br + d;
char b[g];
i = 0;
while (p[i] == '\0') {
if (p[i] == '\0') {
while (p[i] == '\0') {
i++;
}
} else {
b[m] = '\0';
m++;
br1 = 0;
}
b[m] = p[i];
m++;
i++;
br1++;
if (m == g) {
b[m] = '\0';
}
}
printf("%s", b);
}

#include <stdio.h>
void
shuffle (const char *str, unsigned int n) {
unsigned int i = 0;
// loop until the end of the string is found
while (*str) {
// Examine the current character. If it is not a space, output it
// and increment the number of characters output so far in the current word
if (*str != ' ') {
putchar (*str);
++i;
}
// Move to the next character
++str;
// Check if we have output "n" characters so far. If so, output a space to
// separate words and reset the character count
if (i == n) {
putchar (' ');
i = 0;
}
}
// Put a single new line at the end
putchar ('\n');
}
int
main () {
shuffle ("abcd efgh i jk", 3);
}

void f(const char * p, int n) {
char b[n+1];
int i=0;
while(*p){
if(*p == ' '){
++p;
continue;//skip
}
b[i++] = *p++;
if(i % n == 0){
b[i] = '\0';//move out from loop
printf("%s ", b);
i = 0;
}
}
printf("\n");
}

Related

String Pattern Matching in C

I was trying this pattern matching method in C but whenever I give all the input, the vscode terminal waits for a while and just stops the program without any warnings/message. Can anyone point to what is wrong here?
#include <stdio.h>
#include <string.h>
int main()
{
char STR[100], PAT[100], REP[100], ANS[100];
int i, m, j, k, flag, slP, slR, len;
i = m = k = j = flag = len = 0;
printf("\nMain String: ");
gets(STR);
printf("\nPattern String: ");
gets(PAT);
slP = strlen(PAT);
printf("\nReplace String: ");
gets(REP);
slR = strlen(REP);
while (STR[i] != '\0')
{
if (STR[i] = PAT[j])
{
len = 0;
for (k = 0; k < slP; k++)
{
if (STR[k] = PAT[k])
len++;
}
if (len == slP)
{
flag = 1;
for (k = 0; k < slR; k++, m++)
ANS[m] = REP[k];
}
}
else
{
ANS[m] = STR[i];
m++;
i++;
}
}
if (flag == 0)
{
printf("\nPattern not found!");
}
else
{
ANS[m] = '\0';
printf("\nResultant String: %s\n", ANS);
}
return 0;
}
There are multiple problems in the code:
using gets() is risky, this function was removed from the C Standard because it cannot be used safely.
if (STR[i] = PAT[j]) copied the pattern to the string. You should use:
if (STR[i] == PAT[j])
similarly, if (STR[k] = PAT[k]) is incorrect. You should compare PAT[k] and STR[i + k]:
if (STR[i + k] == PAT[k])
you should test for buffer overflow for the output string as replacing a short string by a larger one may produce a string that will not fit in ANS
you do not increment i properly.
Here is a modified version:
#include <stdio.h>
int getstr(const char *prompt, char *dest, int size) {
int c, len = 0;
printf("%s", prompt);
while ((c = getchar()) != EOF && c != '\n') {
if (len + 1 < size)
dest[len++] = c;
}
if (size > 0)
dest[len] = '\0';
printf("\n");
if (c == EOF && len == 0)
return -1;
else
return len;
}
int main() {
char STR[100], PAT[100], REP[100], ANS[100];
int i, m, k, flag;
if (getstr("Main String: ", STR, sizeof STR) < 0)
return 1;
if (getstr("Pattern String: ", PAT, sizeof PAT) < 0)
return 1;
if (getstr("Replace String: ", REP, sizeof REP) < 0)
return 1;
i = m = flag = 0;
while (STR[i] != '\0') {
if (STR[i] == PAT[0]) { // initial match
// compare the rest of the pattern
for (k = 1; PAT[k] != '\0' && PAT[k] == STR[i + k]; k++)
continue;
if (PAT[k] == '\0') { // complete match
flag = 1;
// copy the replacement string
for (k = 0; REP[k] != '\0'; k++) {
if (m + 1 < sizeof ANS)
ANS[m++] = REP[k];
}
i += k; // skip the matching characters
continue;
}
}
// otherwise copy a single character
if (m + 1 < sizeof ANS)
ANS[m++] = STR[i];
i++;
}
ANS[m] = '\0';
if (flag == 0) {
printf("Pattern not found!\n");
} else {
printf("Resultant String: %s\n", ANS);
}
return 0;
}

Segmentation fault error while working with command-line argument, C program

I am working on a program that decodes a message provided as a morse code as a command line argument. If the provided string contains 7 spaces it means that I need to print a space to the decoded string. Currently, my program shows all correct letters, but I cannot overcome the issue with locating 7 spaces in a string and printing one space instead.
Here is the issue and how I pass the encoded string:
e3r2p2% ./morse "..- -.. .-. .. .-- --. ..- ....."
udriwg zsh: segmentation fault ./morse "..- -.. .-. .. .-- --. ..- ....."
Program works fine and prints all the decrypted letters (udriwg) till it meets the first (or maybe second) space out of 7;
Here is the code of my program:
int find_morse(const char *s);
bool count_spaces(char *s);
bool is_valid_char(char *s);
bool is_valid_params(int argc, char *argv[]);
void mx_printchar(char c);
void mx_printerr(const char *s);
int mx_strcmp(const char *first, const char *second);
char* mx_strcpy(char* dest, const char* source);
int mx_strlen(const char *s)
int main(int argc, char *argv[]){
if (!is_valid_params(argc, argv)){
mx_printerr("usage: ./morse \"str\"\n");
exit(1);
}
char *output[27]= {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
"p","q","r","s","t","u","v","w","x","y","z","."};
char *copy;
copy = malloc(mx_strlen(argv[1]) + 1);
if (copy != NULL) {
mx_strcpy(copy, argv[1]);
} else {
mx_printerr("usage: ./morse \"str\"\n");
exit(1);
}
int buff = 0;
char temp[5];
int index;
int space = 0;
int j;
for (int i = 0, n = mx_strlen(copy); i < n; i++) {
if (copy[i] == '.' && copy[i + 1] == '.' && copy[i + 2] == '.'
&& copy[i + 3] == '.' && copy[i + 4] == '.') {
mx_printchar(*output[26]);
}
if (copy[i] != ' ') {
temp[buff] = copy[i];
buff++;
}
if (copy[i] == ' ') {
index = find_morse(temp);
//print letter converted from morse to ENG
mx_printchar(*output[index]);
j = i;
while (copy[j] == ' ') {
space++;
j++;
if (space == 7) {
mx_printchar(' ');
space = 0;
break;
}
}
temp[buff] = '\0';
buff = 0;
for(int j = 0; j <4; j++) {
temp[j] ='\0';
}
}
}
mx_printchar('\n');
free(copy);
return 0;
}
int find_morse(const char *s) {
char *input[27]={".-","-...","-.-.","-..",".","..-.","--.", "....", "..",
".---","-.-",".-..","--","-.", "---",".--.","--.-",".-.",
"...","-","..-", "...-",".--","-..-","-.--","--..","....."};
for (int i = 0; i < 27; i++) {
if (mx_strcmp(s, input[i]) == 0) {
return i;
}
}
return -1;
}
bool count_spaces(char *s) {
int space = 0;
for (int i = 0; s[i] != '\0'; i++) {
if (s[i] == ' ') {
space++;
if (s[i + 1] != ' ') {
if (space != 1 && space != 7) {
return false;
} else {
space = 0;
}
}
}
}
return true;
}
bool is_valid_char(char *s){
int i = 0;
while (s[i] != '\0'){
if (s[i] != ' ' && s[i] != '-' && s[i] != '.') {
return false;
}
i++;
}
return true;
}
bool is_valid_params(int argc, char *argv[]){
if (argc != 2) {
return false;
}
if (!is_valid_char(argv[1])){
return false;
}
if (!count_spaces(argv[1])){
return false;
}
return true;
}
void mx_printchar(char c){
write(1, &c, 1);
}
void mx_printerr(const char *s){
write(2, s, mx_strlen(s));
}
int mx_strcmp(const char *first, const char *second) {
while (*first) {
if (*first != *second) break;
first++;
second++;
}
return *(const unsigned char*)first - *(const unsigned char*)second;
}
char* mx_strcpy(char* dest, const char* source){
if (dest == NULL) {
return NULL;
}
char *ptr = dest;
while (*source != '\0') {
*dest = *source;
dest++;
source++;
}
*dest = '\0';
return ptr;
}
int mx_strlen(const char *s){
int length = 0;
while (s[length] != '\0'){
length++;
}
return length;
}
I believe the issue starts here:
j = i;
while (copy[j] == ' ') {
space++;
j++;
if (space == 7) {
mx_printchar(' ');
space = 0;
break;
}
}
Program prints the decripted letter, then tries to check those spaces but somethis go wrong.
I'd appreciate any suggestions as how to resolve it
When using a program from command line you always put a space as a delimiter between your program name and the parameters and other parameters. So, in your case if there are 7 spaces then a extra space will be added as delimiter between your program name and 7 spaces making it to 8 spaces like this ./morse. So, I'd rather suggest to use any other symbol like ! or any other symbol.
Now for the Segmentation fault error I think that's not happening because of that space counter section that's happening because of this line copy = malloc(mx_strlen(argv[1]) + 1); as you must know that malloc() returns a void * to the allocated space.Now here I don't know what those mx_ functions are. Also some questions popped out in my mind while I was debugging your code those answers are included in the modified code(at somewhat satisfying level) i'm putting below. Please answer them in comments.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Questions
** 1. What are these mx_ functions?
** 2. What is is_valid_params?
** 3. Can't we define *output[27] as *output = "abcdef...z." ?
** 4. In " for(j = 0; j < 4; j++) temp[j] ='\0'; " why j < 4 instead of j < 5?
*/
// Function Prototype
int find_morse(const char *s);
//main()
int main(int argc, char *argv[])
{
char *output[27]= {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","."};
char *copy, temp[5];
int buff = 0, index, space = 0, i, j, n;
// Checking for valid parameters.
if (argc != 2)
{
printf("usage: ./morse \"Invalid Parameters.\"\n");//mx_printerr("usage: ./morse \"str\"\n");
exit(1);
}
copy = (char *)malloc(strlen(argv[1]) + 1);
if (copy != NULL)
strcpy(copy, argv[1]);
else
{
printf("usage: ./morse \"Memory Unavailable.\"\n");
exit(2);
}
for (i = 0, n = strlen(copy); i < n; i++)
{
if (copy[i] == '.' && copy[i + 1] == '.' && copy[i + 2] == '.' && copy[i + 3] == '.' && copy[i + 4] == '.')
putchar(*output[26]);
if (copy[i] != ' ')
temp[buff++] = copy[i];
else
{
j = i;
while (copy[j] == ' ')
{
space++;
j++;
if (space == 7)
{
putchar(' ');
space = 0;
break;
}
}
temp[buff] = '\0';
buff = 0;
// Emptying temp[5]
//for(j = 0; j < 5; j++)
temp[0] = '\0'; // Rest elements will automatically be assigned to \0 by compiler.
}
if(index = find_morse(temp) != -1)
putchar(*output[index]); //print letter converted from morse to ENG
}
putchar('\n');
free(copy);
return 0;
}
int find_morse(const char *s)
{
char *input[27] = {".-","-...","-.-.","-..",".","..-.","--.", "....", "..",".---","-.-",".-..","--","-.", "---",".--.","--.-",".-.","...","-","..-", "...-",".--","-..-","-.--","--..","....."};
for (int i = 0; i < 27; i++)
{
if (strcmp(s, input[i]) == 0)
return i;
}
return -1;
}
Here in this program I didn't understand that how the user will enter morse code one by one or as a string. Because, when matching those morse code entries, I'm sure a logical error would occur.

Compare code in reverse each word in sentence

I have school task. To reverse each word in sentence, so example :
Input: Fried chicken, fried duck.
Output: deirF nekcihc, deirf kcud.
So except dot and comma it's not reversed.
The first code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
int i, n, titik = 0, coma = 0;
char s[5001];
char c[5001];
char *tok;
scanf("%[^\n]s", s);
if (s[0] == ' ')
printf(" ");
tok = strtok(s, " ");
while (tok != NULL) {
strcpy(c, tok);
n = strlen(c);
for (i = n; i >= 0; i--) {
if (c[i] == ',') {
coma = 1;
} else
if (c[i] == '.') {
titik = 1;
} else
printf("%c", c[i]);
}
if (coma) {
printf(",");
coma = 0;
} else
if (titik){
printf(".");
titik = 0;
}
tok = strtok(NULL," ");
if (tok == NULL)
printf("\n");
else
printf(" ");
}
}
Second code is
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main() {
int i, j, n, prana = 0, titik = 0, coma = 0, end = 0;
char s[5001];
scanf("%[^\n]s", s);
n = strlen(s);
for (i = 0; i <= n; i++) {
if (isspace(s[i]) || iscntrl(s[i])) {
if (iscntrl(s[i]))
end = 1;
for (j = i - 1; j >= prana; j--) {
if (s[j] == '.') {
titik = 1;
} else
if (s[j] == ',') {
coma = 1;
} else
printf("%c", s[j]);
}
prana = i + 1;
if (titik) {
titik = 0;
if (end)
printf(".");
else
printf(". ");
} else
if (coma) {
coma = 0;
if (end)
printf(",");
else
printf(", ");
} else {
if (end)
printf("");
else
printf(" ");
}
}
}
printf("\n");
return 0;
}
Why the second code is accepted in test case?, but first code is not.
I tested the result it's same. Really identical in md5 hash.
The output of the two codes id different, because you print the terminating null character for each token in the first code. This loop:
for (i = n; i >=0 ; i--) ...
will have i == n in its first iteration. For a C string of length n, s[n] is the terminating null. This character may not show in the console, but it is part of the output.
To fix the loop, you could start with i = n - 1, but C uses inclusive lower bounds and exclusive upper bounds, and a more idomatic loop syntax is:
i = n;
while (i-- > 0) ...
Not related to your question at hand, but your codes are rather complicated, because they rely on many assumptions: words separated by spaces; only punctuation is comma or stop; repeated punctuation marks are ignored, special case for last word.
Here's a solution that treats all chunks of alphabetic characters plus the apostrophe as words and reverses them in place:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
void reverse(char *str, int i, int j)
{
while (i < j) {
int c = str[--j];
str[j] = str[i];
str[i++] = c;
}
}
int main()
{
char str[512];
int begin = -1;
int i;
if (fgets(str, sizeof(str), stdin) == NULL) return -1;
for (i = 0; str[i]; i++) {
if (isalpha((unsigned char) str[i]) || str[i] == '\'') {
if (begin == -1) begin = i;
} else {
if (begin != -1) {
reverse(str, begin, i);
begin = -1;
}
}
}
printf("%s", str);
return 0;
}

K&R Exe. 1-23 : Some Complications

"Exercise 1-23. Write a program to remove all comments from a C program.
Don't forget to handle quoted strings and character constants
properly. C comments do not nest." K&R pg.34
Basically, I have two questions:
1)I'm completely new coding and I wanted to know if I'm at least thinking the problem the right way.
2)The code was built to ignore // till \n or /* till */. But whit the /* comment it always leaves one /.
Input: abc/*comment*/123
Output: abc/123
Input: abc/*123
Output: abc/
#include <stdio.h>
char s[1000]; //Principal array
int countS; //Number of char in array
int deletSingleLineComments(void);
int deletMultiLineComments(void);
int main(void){
int c;
while((c=getchar())!=EOF){
s[countS]=c;
++countS;
}
deletMultiLineComments(); //Function 1
deletSingleLineComments(); //Function 2
printf("\ns[]=\n%s\n\ncountS[]=%d\n",s,countS);
}
//Functions 1
int deletMultiLineComments(void){
char t[1000];
int i=0;
int inComment=0;
int diff=0;
int a,b,c;
while(i<=countS){
t[i]=s[i];
++i;
}
i=0;
while(i<=countS){
if(t[i]=='/' && t[i+1]=='*'){
inComment=1;
}
if(inComment==1){
++diff; //to equilibrate the number
}
if(inComment==0){
s[i-diff]=t[i];
}
if(t[i]=='*' && t[i+1]=='/'){
inComment=0;
}
++i;
}
s[i-diff+1]='\0';
countS=i-diff;
printf("\nt[]=\n%s\n",t);
}
//Function 2
int deletSingleLineComments(void){
int i=0;
char t[1000];
int inComment=0;
int diff=0;
while(i<=countS){
t[i]=s[i];
++i;
}
i=0;
while(i<=countS){
if(t[i] == '/' && t[i+1] == '/'){
inComment=1;
}
if(t[i]=='\n'){
inComment=0;
}
if(inComment==1){
++diff;
}
if(inComment==0){
s[i-diff]=t[i];
}
s[i-diff+1]='\0';
++i;
}
countS=i-diff;
}
Thank you.
while(i<=countS){ t[i]=s[i];... }
Note that character strings are zero based. For example "ABC" has length 3, it starts at zero index, and the last valid index is 2 (not 3). Therefore you should change the condition to i < string_length
while(i < countS){ t[i]=s[i];... }
Also be careful when accessing t[i+1], because while i is valid, i+1 can be out of bound.
if (i < (countS - 1))
if(t[i]=='/' && t[i+1]=='*')
In order to assign one string to another, you can introduce a second variable k, and increment k after each assignment. This method is easier (in my opinion) than using the diff variable and doing additions and subtractions.
In addition, rather than char t[1000];, you can use char *t = malloc(countS); to declare a temporary variable of length countS, then it has to be freed at the end with free(t). If your compiler supports variable length array, you can just put char t[countS].
Example:
char s[1000]; //Principal array
int countS; //Number of char in array
//Functions 1
void deletMultiLineComments(void)
{
char *t = malloc(countS);
int i = 0;
int k = 0;
int inComment = 0;
while (i < countS)
{
t[i] = s[i];
++i;
}
i = 0;
while (i < countS)
{
if (i < countS - 1)
if (t[i] == '/' && t[i + 1] == '*')
{
inComment = 1;
i+=2;
continue;
}
if (inComment == 1)
{
if (i < countS - 1)
if (t[i] == '*' && t[i + 1] == '/')
{
inComment = 0;
i+=2;
continue;
}
}
if (inComment == 0)
{
s[k] = t[i];
k++;
}
++i;
}
free(t);
s[k] = '\0';
countS = k;
printf("mulitline comment removed %s\n", s);
}
//Function 2
void deletSingleLineComments(void)
{
char *t = malloc(countS);
int i = 0;
int k = 0;
int inComment = 0;
while (i < countS)
{
t[i] = s[i];
++i;
}
i = 0;
while (i < countS)
{
if (i < countS - 1)
if (t[i] == '/' && t[i + 1] == '/')
{
inComment = 1;
i += 2;
continue;
}
if (t[i] == '\n')
{
inComment = 0;
}
if (inComment == 0)
{
s[k] = t[i];
k++;
}
i++;
}
free(t);
s[k] = '\0';
countS = k;
printf("single comment removed %s\n", s);
}
int main(void)
{
//get input
scanf("%s", s);
countS = 0;
while (s[countS]) countS++;
deletMultiLineComments(); //Function 1
deletSingleLineComments(); //Function 2
}

Infinite loop in C counting spaces

I'm writing a program to count spaces and vowels and it didnĀ“t work, I think I did an infinite loop.I'll show you my code:
int contar_p(char a[100]) {
int i = 0, spaces = 1;
while (a[i] != '\0' && i < 100) {
if (a[i] == ' ') {
spaces += 1;
i++;
}
}
return spaces;
}
int contar_v(char b[100]) {
int i = 0, counter = 0;
while (b[i] != '\0' && i < 100) {
if (b[i] == 'a' || b[i] == 'e' || b[i] == 'i' || b[i] == 'o' || b[i] == 'u') {
counter += 1;
}
i++;
}
return counter;
}
int main(void){
char phrase[100];
int words = 0, vowels = 0;
printf("write a phrase ");
gets(phrase);
palabras = contar_p(phrase);
vocales = contar_v(phrase);
printf("%d\n", words);
printf("%d", vowels);
return 0;
}
The loop
while (a[i]!='\0'&&i<100){
if(a[i]==' '){
spaces+=1;
i++;
}
}
is an infinite loop. Place i++ outside the if. Change it to
while (a[i]!='\0'){ // No need of condition i < 100
if(a[i]==' '){
spaces+=1;
}
i++;
}
Maybe another approach will help you to understand things easier, i'm mean you do know that there are A,E,I,O,U also and not only a,e,i,o,u. You should never use gets instead use fgets, anyway take a look at the following program:
#include <stdlib.h>
#include <stdio.h>
void countVowels(char* array){
int i,j,v;
i=0;
int count = 0;
char vowel[]={'a','e','i','o','u','A','E','I','O','U'};
while(array[i]!='\0'){
for(v=0;v<10;v++){
if (array[i]==vowel[v]){
j=i;
while(array[j]!='\0'){
array[j]=array[j+1];
j++;
}
count++;
i--;
break;
}
}
i++;
}
printf("Found %d Vowels\n",count);
}
void contar_p(char a[100]) {
int i = 0, spaces = 0;
for(i=0;a[i]!='\0';i++){
if(a[i]==' ')
spaces++;
}
printf("Found %d Spaces\n",spaces);
}
int main(void){
char a[]="aa bb EOU cc ii";
countVowels(a);
contar_p(a);
return 0;
}
Output:
Found 7 Vowels
Found 4 Spaces

Resources