manipulating string in c [closed] - c

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 8 years ago.
Improve this question
I am trying to take a string input from user and then reverse only the words starting with a vowel.Then reprint the changed string.I have used the strtok() function to separate the words from the string.But reversing the words,seems to be a problem....I have written a code for this program,but it is having runtime error.So,it will be really useful,if anyone could help me correct my code or provide me with a solution.
Here is my code:
#include <stdio.h>
#include <string.h>
void reverse(char *tok);
int length(char *t);
int main()
{
char sen[50];
const char s[2] = " ";
int i;
printf("Enter a Sentence: ");
gets(sen);
char *token;
token = strtok(sen, s);
printf("Output: ");
while (token != 0)
{
char z[20] =
{ *token };
for (i = 0;; i++)
{
if (z[i] == ' ')
{
z[i] = '\0';
break;
}
}
if (z[0] == 'a' || z[0] == 'A' || z[0] == 'e' || z[0] == 'E' || z[0] == 'i'
|| z[0] == 'I' || z[0] == 'o' || z[0] == 'O' || z[0] == 'u'
|| z[0] == 'U')
{
reverse(token);
}
else
printf("%s ", *token);
token = strtok(NULL, s);
}
printf("\n");
return 0;
}
//function for reversing the particular parts of string
void reverse(char *tok)
{
char x[20] =
{ *tok };
int i, j, len;
char temp;
for (i = 0;; i++)
{
if (x[i] == ' ')
{
x[i] = '\0';
break;
}
}
len = length(tok);
j = len - 1;
for (i = 0; x[i] != len / 2; i++)
{
temp = x[i];
x[i] = x[j];
x[j] = temp;
j--;
}
printf("%s", x);
printf(" ");
}
//function for determining the length of the token string
int length(char *t)
{
int i = 0;
char y[20] =
{ *t };
for (;; i++)
{
if (y[i] == ' ')
{
y[i] = '\0';
break;
}
}
while (y[i] == '\0')
{
i++;
}
return i;
}

This line
printf("%s ", *token);
passes a char where a 0-terminated char[] is expected.
The lesson learned is: Always compile with all warnings on! (-Wall -Wextra -pedantic for gcc)

Problem lies in this line:
if(z[i]==' ')
You've split with the token ' ', so that means there is no ' ' in z[]. So the loop never ends.

#include <stdio.h>
#include <string.h>
void reverse(char *tok);
int length(char *t);
int main(){
char sen[50];
const char s[2] = " ";
printf("Enter a Sentence: ");
scanf("%49[^\n]", sen);//gets(sen); //"gets" : Obsolete !
char *token = strtok(sen, s);
printf("Output: ");
while (token != NULL){
char z = *token;
if (z == 'A' || z == 'E' || z == 'I' || z == 'O' || z == 'U' ||
z == 'a' || z == 'e' || z == 'i' || z == 'o' || z == 'u'){
reverse(token);//print by this function
} else {
printf("%s ", token);
}
token = strtok(NULL, s);
}
printf("\n");
return 0;
}
void reverse(char *tok){//original not change
int i, len = length(tok);
char x[len + 1];
for (i = 0; i<len; ++i){
x[i] = tok[len-i-1];
}
x[i]='\0';
printf("%s ", x);
}
int length(char *t){//use strlen
int i;
for(i=0;*t;++i, ++t)
;
return i;
}

Related

Reverse the words in a sentence using two while loops

I cant get the right output and I wonder where my mistake is. Probably there are mistakes in loops in the counting reverse. The main problem in my whole code is that it only outputs marks but not words. Also the program must end automatically when putting these three punctuation and shows the output.
This is the expected behavior:
Input: my name is jake.//terminates when putting . and automatically shows the output
Output: jake is name my.
Here is the program fragment of my first loop:
#include <stdio.h>
#define N 70
int main(void) {
char array[N] = { 0 };
char *p;
char mark = 0;
int c;
p = array;
scanf("%d", &c);
while ((c = getchar()) != '\n') {
if (p < array + N) {
if (c == '.' || c == '!' || c == '?')
mark = c;
if (c == ' ') {
*p = '\0';
*p++;
} else
*p = c;
}
}
*p = '\0';
while (--p > array) {
if (p[1])
printf("%s", p + 1);
}
printf("%s", array);
if (mark)
printf("%c", mark);
}
Your code with little modifications:
#include <stdio.h>
#define N 70
int main (void) {
char array[N+1] = { 0 };
char* p;
char mark = 0;
int c;
p = array;
//scanf ("%d", &c); //serves no purpose : are you reading sentence length here?
while ( (c = getchar()) != '\n') {
if (p < array + N) {
if (c == '.' || c == '!' || c == '?') {
mark = c;
*p++ = '\0';
break; // stop reading input
} else if (c == ' ') {
*p++ = '\0';
} else
*p++ = c;
}
}
*p = '\0';
while (--p > array) {
if ('\0' == *p && '\0' != *(p + 1))
printf ("%s ", p + 1);
}
printf ("%s", array);
if (mark)
printf ("%c", mark);
return 0;
}
There is a better way, but that will make use of string library functions.
Here is an alternative where the original string is not modified:
#include <stdio.h>
#include <string.h>
void print_swap(const char *s) {
int p1, p2, tail = strcspn(s, ".!?\n");
for (p1 = p2 = tail; p1 > 0; p1--) {
if (s[p1 - 1] == ' ') {
printf("%.*s ", p2 - p1, s + p1);
p2 = p1 - 1;
}
}
printf("%.*s%s", p2, s, s + tail);
}
int main() {
char array[80];
if (fgets(array, sizeof array, stdin))
print_swap(array);
return 0;
}

How do I remove duplicate vowels from a string?

Question: Define an int function that removes all consecutive vowel repetitions from a string. The function should return the number of vowels removed and present the string without duplicates.
I am PT so Vogais is Vowels; Digite uma String is Write one String. A String sem duplicados fica assim ' %s ' e foram retiradas %d vogais is The string without duplicates is ' %s ' and where removed %d vowels.
Explanation: In portuguese we have some words with two consecutive vowels like: coordenador, coordenação (chqrlie example). But in thouse cases should be ignored in the context of this problem.
Problem: When I test a string like 'ooooo' it says the string without duplicate vogals is 'oo' and where removed 3 vowels. But it should be 'o' and 4 vowels removed. Another example with error is 'Estaa e umaa string coom duuuplicadoos', I am getting ' Esta e uma string com duplcdos ' and 8 vowels removed.
Note: This is a simple question so there isn't need to complicate. It only askes the consecutive duplicate vowels. The cases 'oOoO' -> 'oO' ,'abAb'->'abAb','abab' -> 'ab','aba'-> 'aba',... are in another chapter XD.
int Vogais(char *s) {
if (*s == 'A' || *s == 'a' || *s == 'E' || *s == 'e'
|| *s == 'I' || *s == 'i' || *s == 'O' || *s == 'o'
|| *s == 'U' || *s == 'u') return 1;
return 0;
}
int retiraVogaisRep(char *s) {
int res = 0;
for (int i = 0; i < strlen(s); i++) {
for (int j = i + 1; s[j] != '\0'; j++) {
if (s[i] == s[j] && Vogais(&s[j]) == 1) {
res++;
for (int k = j; s[k] != '\0'; k++) {
s[k] = s[k + 1];
}
}
}
}
return res;
}
int main() {
char s[38];
printf("Digite uma String:\n");
scanf("%[^\n]", s);
int res = retiraVogaisRep(s);
printf("A String sem duplicados fica assim ' %s ' e foram retiradas %d vogais.\n", s, res);
return 0;
}
Your code is too complicated: there is no need for nested loops for this task and you do not set the null terminator when shortening the string.
Here is a simpler version:
#include <stdio.h>
#include <string.h>
int retiraVogaisRep(char *s) {
int i, j; // use 2 running indices
char c, last = 0;
for (i = j = 0; (c = s[i]) != '\0'; i++) {
if (c != last || !strchr("aeiouAEIOU", c))
s[j++] = last = c;
}
s[j] = '\0'; // set the null terminator
return i - j; // return the number of bytes removed
}
int main() {
char s[100];
printf("Digite uma String:\n");
// read the user input safely with `fgets()`
if (!fgets(s, sizeof s, stdin))
return 1;
// strip the trailing newline if any
s[strcspn(s, "\n")] = '\0';
// remove duplicate consecutive vowels
int res = retiraVogaisRep(s);
printf("A String sem duplicados fica assim ' %s ' e foram retiradas %d vogais.\n", s, res);
return 0;
}
The question tag is C, but I will not post the actual code here.
The pseudocode:
function is_vowel(int c) {...}
start loop c = <src>
if next_char is past the last char then quit loop;
if is_vowel(c) and c == next_char and is_vowel(next_char)
then continue;
else
copy c to <dst>
You should elaborate on this, as the above is possibly having small issues. Nevertheless, I think this answer is somewhat shorter and gives an insight.
Update
The above is definitly have an issue, in that the next char does not copied to the output. The mistake is easy to correct, so I will leave it up to OP.
Update
Edited above code to indicate that OP wants to remove only identical duplicates. So, the case of a charcter is important.
Rather than a triple nested loop, consider a single walk down the string, looking for repeats.
#include <stdio.h>
#include <ctype.h>
int Vogais(unsigned char s) {
if (s == 'A' || s == 'a' || s == 'E' || s == 'e'
|| s == 'I' || s == 'i' || s == 'O' || s == 'o'
|| s == 'U' || s == 'u') return 1;
return 0;
}
int retiraVogaisRep(char *s) {
unsigned char *us = (unsigned char *) s;
unsigned char *dest = us;
int res = 0;
int prior = EOF;
while (*us) {
while (toupper(*us) == prior) {
us++;
res++;
}
prior = Vogais(*us) ? toupper(*us) : EOF;
*dest++ = *us++;
}
*dest = '\0';
return res;
}
int main() {
char buf[100] = "OoFreedaa";
printf("%d\t", retiraVogaisRep(buf));
printf("<%s>\n", buf);
return 0;
}
Output
3 <OFreda>
Remove consecutive duplicate vowels
You should use tolower function from ctype.h to check for vowels, that include the letter 'y', see below working code:
You can store previous character in prev and compare it to the current character, as you are case insensitive you store the tolower version.
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int Vogais(char c){
return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y') ;
}
int retiraVogaisRep (unsigned char *s){
if (*s == NULL)
return 0;
unsigned char t[256];
memset(t, 0, sizeof(t));
int res = 0;
int j = 0;
t[0] = s[0];
char prev = tolower(s[0]);
int len = strlen(s);
for (int i = 1; i < len; i++) {
char c = tolower(s[i]);
if (Vogais(c) && c == prev)
++res;
else
t[j++] = s[i];
prev = c;
}
memcpy(s, t, sizeof(t));
return res;
}
int main(){
char s[256];
printf("Digite uma String:\n");
scanf("%255[^\n]", s);
int res = retiraVogaisRep(s);
printf("Da String ' %s ' podem ser retiradas %d vogais.\n", s,res);
return 0;
}
Retaining the uppercase, using the Kernighan-copy
#include <stdio.h>
#include <string.h>
#include <ctype.h>
size_t remove_duplicate_vowels(char *str)
{
int old,new;
size_t dst,src;
old = 0;
for(dst=src=0; str[dst] = str[src]; old=new, src++ ) {
new = toupper( str[dst] );
if ( !strchr( "AEIOU", new )) { // Not a vowel
dst++; continue;
}
if ( new != old ) { // Not a repetition
dst++; continue;
}
}
return src - dst;
}
int main(int argc, char **argv)
{
char test[] = "Aaa bbBb CccCC d eEeee!";
char *arg;
size_t ret;
arg = argv[1] ? argv[1] : test;
ret = remove_duplicate_vowels(arg);
fprintf(stderr, "[%zu]: %s\n", ret, arg);
return 0;
}

cant free dynamic matrix

As a part of my homework with C, I had to make a function which splits a string to all the words starting with the key(which is a letter) inserted.
Everything works great except for the free function,
When I try to free the dynamic matrix by function (rows and then skeleton)
I get an error that the program has triggered a breakpoint.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char **Split(char *str, char letter, int *size);
void free_mat(char **mat, int size);
int main() {
int size, i;
char letter;
char STR[100];
char **strings_arr;
printf("Please enter a string:\n");
flushall;
gets(STR);
printf("Please enter a letter for a check:\n");
letter = getchar();
strings_arr = Split(STR, letter, &size);
if (size > 0) {
printf("The number of words that starts with the letter '%c' in the string '%s' is: %d\n\n", letter, STR, size);
}
printf("The words are:\n");
for (i = 0; i < size; i++) {
printf("%d . %s\n", i+1,strings_arr[i]);
}
free_mat(strings_arr, size);
return 0;
}
void free_mat(char **mat, int size)
{
int i;
for (i = 0; i < size; i++)
{
free(mat[i]);
}
free(mat);
}
char **Split(char *str, char letter, int *size) {
int rows = 0, i, lengh = 0, j = 0, n = 0, m;
char **strings_array;
if ((str[0] == letter) || (str[0] == letter + 32) || str[0] == letter - 32) {
rows++;
}
for (i = 0; str[i] != '\0'; i++) {
if (str[i] == ' ') {
if ((str[i + 1] == letter) || (str[i + 1] == letter + 32) || str[i + 1] == letter - 32) {
rows++;
}
}
}
if (rows == 0) {
printf("There are no words starting with '%c' letter in this string\n\n", letter);
}
i = 0;
strings_array = (char*)malloc(rows * sizeof(char));
if ((str[0] == letter) || (str[0] == letter + 32) || str[0] == letter - 32) {
while (str[i] != ' ' && str[i] != '\0') {
lengh++;
i++;
}
strings_array[j] = (char*)malloc((lengh + 1) * sizeof(char));
for (n = 0; n < lengh; n++) {
strings_array[j][n] = str[n];
}
strings_array[j][n] = '\0';
j++;
}
for (i = 1; str[i] != '\0'; i++) {
if (letter == str[i] || letter == str[i] - 32 || letter == str[i] + 32) {
lengh = 0;
//k = 0;
m = i;
while (str[m] != ' ' && str[m] != '\0') {
lengh++;
m++;
}
strings_array[j] = (char*)malloc(lengh + 1);
for (n = 0; n < lengh; n++) {
strings_array[j][n] = str[i++];
}
strings_array[j][n] = '\0';
j++;
}
}
*size = rows; // sends back the number of words by referance
return strings_array;
}
Thanks!
A breakpoint is something that you manually insert in the code from your IDE or equivalent. It is used for debugging. When you run the code it is intended to stop when it reaches a breakpoint. So just remove the breakpoint and it should work as expected.
Note: Remove only the breakpoint. Not the code on that line.
You mentioned in comments below that you're using Visual Studio 2015. Here is the documentation for breakpoints in that software: https://learn.microsoft.com/en-us/visualstudio/debugger/using-breakpoints?view=vs-2019
But there are some other things about your code. First of all, use fgets instead of gets. Second, you seem to have posted the wrong version or something, because free_mat will not compile. However, that was easily solved by changing arr to mat.
There's also another error that xing mentioned in the comments. Change strings_array = (char*)malloc(rows * sizeof(char)) to strings_array = malloc(rows * sizeof(*strings_array)). The cast is not necessary, you picked the wrong type for the argument to sizeof and if you pass a dereferenced pointer instead of the type you'll save yourself a lot of problems in the future.

Splitting word by specific char work with string but don't work with argv[1]

I have an issue with my program.
My program split word using \t \n or space and put the word into a array of string.
when i call my function like this its works perfectly :
ft_print_words_tables(ft_split_whitespaces("Hello Everyone this is a test"));
but when i try to send the first command line param like this :
ft_print_words_tables(ft_split_whitespaces(argv[1]));
i'm getting the following error :
./a.out "test test tast"
a.out(97132,0x7fff706ff000) malloc: * error for object 0x7f9e09403228: incorrect checksum for freed object - object was probably modified after being freed.
* set a breakpoint in malloc_error_break to debug
[1] 97132 abort ./a.out "test test tast"
here is the code :
#include <stdlib.h>
// This func return the word nbr
int ft_compte_mot(char *str) {
int i = 0;
int j = 0;
while(str[i] == ' ' || str[i] == '\t' || str[i] == '\n') {
i++;
while (str[i] != '\0') {
if ((str[i] == ' ' || str[i] == '\n' || str[i] == '\t') &&
(str[i + 1] >= '!' && str[i + 1] <= 'z')) {
j++;
}
i++;
}
return (j + 1);
}
// this func count the word lenght and put them in an int array
int *ft_compte_taille_mot(int *taillemot, char *str) {
int i = 0;
int j = 0;
int k = 0;
while (str[i] != '\0') {
j = 0;
while ((str[i] == ' ' || str[i] == '\n' || str[i] == '\t')
&& str[i] != '\0')
i++;
while (str[i] != ' ' && str[i] != '\n' && str[i] != '\t'
&& str[i] != '\0') {
j++;
i++;
}
taillemot[k] = j;
i++;
k++;
}
return (taillemot);
}
void ft_copy_word(int *taillemot, int nbmot, char **tab, char *str) {
int i = 0;
int j = 0;
int k = 0;
while (str[i] != '\0' && k < nbmot) {
j = 0;
while ((str[i] == ' ' || str[i] == '\n' || str[i] == '\t')
&& str[i] != '\0')
i++;
while (j < taillemot[k]) {
tab[k][j] = str[i];
j++;
i++;
}
//tab[k][j] = '\0';
i++;
k++;
}
tab[nbmot] = 0;
}
char **ft_split_whitespaces(char *str) {
int nbmot = ft_compte_mot(str);
int *taillemot;
int i = 0;
char **string;
if ((taillemot = (int*)malloc(sizeof(int) * nbmot)) == NULL)
return (NULL);
ft_compte_taille_mot(taillemot, str);
if ((string = (char **)malloc(sizeof(char *) * (nbmot + 1))) == NULL)
return (NULL);
while (i < nbmot) {
if ((string[i] = (char *)malloc(sizeof(char) * taillemot[i] + 1))
== NULL)
return (NULL);
i++;
}
ft_copy_word(taillemot, nbmot, string, str);
return (string);
}
void ft_putchar(char c) {
write(1, &c, 1);
}
void ft_putstr(char *str) {
int i = 0;
while (str[i] != '\0') {
ft_putchar(str[i]);
i++;
}
}
void ft_print_words_tables(char **tab) {
int i;
i = 0;
while (tab[i] != 0) {
ft_putstr(tab[i]);
ft_putchar('\n');
i++;
}
ft_putchar('\n');
}
EDIT : Here is the main EDIT 2 : I also tested with argv[1]
char **ft_split_whitespaces(char *str);
void ft_print_words_tables(char **tab);
void ft_putchar(char c)
{
write(1, &c, 1);
}
int main(int argc, char **argv)
{
ft_print_words_tables(ft_split_whitespaces(argv[1]));
return (0);
}
FYI i'm in school and we have a particular norm, we can't use for loop or a bunch of libc function.
I'm really stuck here and i really don't understand why it's work with " " but not with **argv
thx by advance for your help
I found the solution :
char *str;
str = argv[1];
str[strlen(str) + 1] = '\0';
ft_print_words_tables(ft_split_whitespaces(str));
return (0);
thanks for the help

Need to take multiple digit input from a string removing spaces and alphabets

I am writing a program where I am taking string as an input, here I need to remove spaces , ignore alphabets and use only numerals.
I am able to achieve removing spaces and alphabets, but i can only use single digits and not multiple digits.
Example:Input string:"adsf 12af 1 a123c 53c2m34n"
Here I need to use the input as "12 1 123 54234" required for my application.
It will be great some one could share the logic or the sample code for the same.
Thanks in advance
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int pullOut(const char *str, int array[], int *size){
const char *p = str, *endp;
int pull, count = 0, max = *size, num;
do{
endp=strchr(p, ' ');
if(endp == NULL)
endp=strchr(p, '\0');
for(num=pull=0; p != endp; ++p){
if(isdigit(*p)){
num = num * 10 + *p - '0';
pull = 1;
}
}
if(pull && count < max)
array[count++] = num;
while(*p == ' ')
++p;//skip sapce
}while(*endp != '\0');
return *size = count;
}
int main(void){
char input[] = "adsf 12af 1 a123c 53c2m34n abc def";
int i, arr[128] = { 0 }, arr_num = sizeof(arr)/sizeof(int);
pullOut(input, arr, &arr_num);
for(i = 0; i < arr_num ; ++i)
printf("%d\n", arr[i]);
return 0;
}
int i = 0;int j = 0;
while (input[i])
{
if (input[i] == ' ' || (input[i] >= '0' && input[i] <= '9'))
newString[j++] = input[i];
i++;
}
newString[j] = '\0';
If you do this, you'll copy only numerics and space into newString. I let you do all the memory alloc stuff.
here is your func:
void remove_func(char *str)
{
int i;
i = 0;
while(str[i])
{
if(str[i] >= '0' && str[i] <= '9')
{
putchar(str[i]);
i++;
}
else if(str[i] == ' ' && str[i + 1] != ' ')
{
putchar(str[i]);
i++;
}
else
i++;
}
}
What about this one:
char * getNumbers(const char *src, char *dst)
{
int j=0,i=0;
while (i < strlen(src))
{
if (src[i] >= '0' && src[i] <= '9')
{
dst[j++]=src[i++];
}
else
{
// skip duplicates spaces
if (j > 0 && src[i] == ' ' && dst[j-1] != ',') dst[j++]=',';
i++;
}
}
// remove the trailing ',' if exists
if (j > 0 && dst[j-1] == ',') j--;
dst[j]='\0';
return dst;
}
char src[] = "adsf 12af 1 a123c 53c2m34n";
char dst[sizeof(src)];
getNumbers(src, dst);
printf("'%s' -> '%s'\n", src, dst);
output:
'adsf 12af 1 a123c 53c2m34n' -> '12,1,123,53234'

Resources