I do this program which receives input from a string and a substring, and then searches for the substring within the string by determining how often it appears (the number of occurrences) and the locations it is located, then these positions are inserted into an array for example (4 5 8) And they are printed correctly, now what I was trying to do, once I got my array with inside the locations where the substring was found it print it in reverse ie (8 5 4) I tried using this cycle
// reverse output
printf ("%d", count);
for (j = count - 1; j >= 0; j--)
printf("%d", pos[j]);
But if the array positions are 8 5 4 so it prints to me
5 ,4, -311228772
Why does this happen? Here is the code:
// inclusion of libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Reads a string allocated by the stream.
It stops at newline, not included in string.
Returns NULL to EOF
*/
char *my_getline(FILE *stream) { // statement of function
char *line = NULL; // this is just the pointer initialization
size_t pos = 0; // definition of position variables and init
int c; // a variable to store the temporary character
while ((c = getc(stream)) != EOF) // read every character until the end of the file
{
char *newp = realloc(line, pos + 2); // To dynamically allocate memory, with reference to the number of characters and more '2' is only to compensate for the null character and the character (since it is 0)
if (newp == NULL) { // checks whether memory has been properly associated or not.
free(line); // if the line is not free the blank
return NULL; // interrupts the program and returns NULL
}
line = newp; // if memory is allocated correctly stores the memory allocated to the line pointer
if (c == '\n') // if a new line is detected
break; // interrupts the while cycle
line[pos++] = (char)c; // stores the character in dynamic memory and the new character in the new location.
}
if (line) { // if the line contains something then a null character is added at the end to complete that string.
line[pos] = '\0';
}
return line; // returns the contents of the line.
}
int main(void) { // main statement
char *str, *sub; // character punctuation statement
size_t len1, len2, i, count = 0; // unsigned value statement "size_t is equal to unsigned int" so may also be <0
int pos[count]; // declare a count array to insert the index then print it in reverse
int j;
// Here is the main string
printf("Enter Main String: \n"); // print the entry and enter the main string
str = my_getline(stdin); // inserts the entered string inside the pointer using my_getline function and using getchar analogue stdin to make the entered characters input from the standard input
// here is the substring to look for
printf("Enter substring to search: \ n"); // print the entry and enter the main substring
sub = my_getline(stdin); // inserts the entered string inside the pointer using my_getline function and using getchar analogue stdin to make the entered characters input from the standard input
if (str && sub) { // if string and substring && = and
len1 = strlen(str); // inserts the string length in the len1 variable
len2 = strlen(sub); // inserts the length of the string in the len2 variable
for (i = 0; i + len2 <= len1; i++) { // loop for with the control that the substring is less than or equal to the main string ie len2 <= len1
if (! memcmp(str + i, sub, len2)) { // here uses the memcmp function to compare the string and substring byte bytes
count++; // count variable that is incremented each time the sub is found in p
// here is where it gets in output
// If the substring was found mold the index with the locations it was found
pos[count] = i + 1;
printf( "%d\n", pos[count]);
}
}
// print to get reverse output
printf("number of times%d", count);
// print to get reverse output
printf("%d", count);
for (j = count - 1; j >= 0; j--)
printf("%d", pos[j]);
if (count == 0) { // if count is = 0 ie the substring was not found string string not found
// otherwise if not found
printf("Subtry not found \n");
}
}
// free releases the memory area that was reserved for the string and substrings so that it can be reused in the next run
free(str);
free(sub);
return 0; // exit analog
}
Your code is completely unreadable. Even reformatted and spaced out, the comments make it difficult to see the important stuff.
You should only comment the non obvious: int main(void) {// main statement is a good example of a useless counter productive comment.
After removing all comments, the code shows a few problems:
There is an extra space in printf("Enter substring to search: \ n");
The array pos is defined with a size of 0: int count = 0; int pos[count];. The program has undefined behavior.
count is incremented before storing the offset into the array. Hence the array contents does not start at index 0, hence producing incorrect output when you iterate from count-1 down to 0 in the second loop.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Reads a string from the stream allocated with malloc
stops at newline, not included in string.
Returns NULL at EOF
*/
char *my_getline(FILE *stream) {
char *line = NULL;
size_t pos = 0;
int c;
while ((c = getc(stream)) != EOF) {
char *newp = realloc(line, pos + 2);
if (newp == NULL) {
free(line);
return NULL;
}
line = newp;
if (c == '\n')
break;
line[pos++] = (char)c;
}
if (line) {
line[pos] = '\0';
}
return line;
}
int main(void) {
printf("Enter Main String:\n");
char *str = my_getline(stdin);
printf("Enter substring to search:\n");
char *sub = my_getline(stdin);
if (str && sub) {
size_t count = 0;
size_t len1 = strlen(str);
size_t len2 = strlen(sub);
size_t pos[len1 + 1];
for (size_t i = 0; i + len2 <= len1; i++) {
if (!memcmp(str + i, sub, len2)) {
pos[count] = i + 1;
printf("%d\n", (int)pos[count]);
count++;
}
}
if (count != 0) {
printf("number of times: %d\n", (int)count);
for (size_t j = count; j-- > 0;) {
printf(" %d", (int)pos[j]);
}
printf("\n");
} else {
printf("substring not found.\n");
}
}
free(str);
free(sub);
return 0;
}
You declared pos as an array of length 0:
size_t ... count = 0;
int pos [count];
Thus, inside your for-loop you'll access some unitialized memory:
for (j = count-1; j>= 0; j--)
printf ("%d", pos [j]);
Related
The code: https://pastebin.com/nW6A49ck
/* C program to remove consecutive repeated characters from string. */
#include <stdio.h>
int main() {
char str[100];
int i, j, len, len1;
/* read string */
printf("Enter any string: ");
gets(str);
/* calculating length */
for (len = 0; str[len] != '\0'; len++);
/* assign 0 to len1 - length of removed characters */
len1 = 0;
/* Removing consecutive repeated characters from string */
for (i = 0; i < (len - len1);) {
if (str[i] == str[i + 1]) {
/* shift all characters */
for (j = i; j < (len - len1); j++)
str[j] = str[j + 1];
len1++;
} else {
i++;
}
}
printf("String after removing characters: %s\n", str);
return 0;
}
The problem: Lets say I have the string 'Hello' as an input..I want the two ls to be both removed (not only 1)... Same for 'Helllo' (I want the 3 ls to be removed and not just the 2 ls)... How can I do that?
if (str[i] == str[i + 1]) {
/* shift all characters */
for (j = i; j < (len - len1); j++)
str[j] = str[j + 1];
len1++;
}
Maybe I can count the times every character is repeated and then in line 28 replace 1 with the the times a character is repeated? But how can I implement this to the code?
You could make a function to remove the ranges with equal characters by copying character by character to a separate pointer in the string that you do not step forward if repeating characters are found:
void foo(char *str) {
for(char *wr = str; (*wr = *str) != '\0';) { // copy until `\0` is copied
++str; // step to the next character
if(*wr != *str) { // if the next char is not equal to `*wr`
++wr; // step `wr` forward to save the copied character
} else do {
++str; // `*wr == *str`, so step `str` forward...
} while(*wr == *str); // ...until a different character is found
}
}
*wr = *str copies the current character str is pointing at to where wr is currently poining. The != '\0' check makes the loop end when \0 (the null terminator) has been copied.
After that str is increased to point at the next character.
If the next character is not equal to the one which was just copied, increase wr to save that copied character.
If the next character was indeed equal to the one being copied, don't increase wr to let it be overritten by the next character being copied and step str forward until a different character is found.
Demo
A dense version doing exactly the same thing:
void foo(char *str) {
for(char *wr = str; (*wr = *str) != '\0';) {
if(*wr != *++str) ++wr;
else while(*wr == *++str);
}
}
This code snippet should remove all consecutive characters out of your string (note that some C compilers won't let you declare variables within the internal blocks):
for (int i=0; i<len; i++) {
int j = i, repeats = 1;
while (j < len-1 && str[j] == str[++j])
{
repeats++;
}
if (repeats > 1) {
for (j = i; j < len - repeats; j++)
{
str[j] = str[j + repeats];
}
len -= repeats;
i--;
str[len] = '\0';
}
}
Links are discouraged, instead, you should post the contents of link. Also, for such kind of problem, I will suggest first come up with an appropriate algorithm and then implement it. At time, you will find it much more easier than taking someone else's code and making changes to it make it work as per your need.
Algorithm:
Step I: Record the position where the letter to be written in the string (calling this position - P). Initially, it will be start of string.
Step II: If current processing character is same as it's next character, then
Dont make any change in P.
Set a flag to skip next character (calling this flag - F).
Step III: If current processing character and next character are different, then
If flag F is set, skip this character, reset flag F and don't change P.
If flag F is not set then write this character at position P in the string and set P to next position.
Step IV: Move to next character in the string and go to Step II.
Implementation:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void remove_all_consecutive_dup_chars (char * pstr) {
if (pstr == NULL) {
printf ("Invalid input..\n");
return;
}
/* Pointer to keep track of position where next
* character to be write.
*/
char * p = pstr;
int skip_letter = 0;
for (unsigned int i = 0; pstr[i] ; ++i) {
/* Using tolower() to identify the consecutive characters
* which are same and only differ in case (upper/lower).
*/
if ((tolower (pstr[i]) == tolower (pstr[i + 1]))) {
skip_letter = 1;
continue;
}
if (skip_letter) {
skip_letter = 0;
} else {
*p++ = pstr[i];
}
}
/* Add the null terminating character.
*/
*p = '\0';
}
int main (void) {
char buf[256] = {'\0'};
strcpy (buf, "WELL, well, welLlLl....");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
strcpy (buf, "Hello");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
strcpy (buf, "Helllo");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
strcpy (buf, "aAaaaA ZZz");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
return 0;
}
Output:
# ./a.out
WELL, well, welLlLl.... ----> WE, we, we
Hello ----> Heo
Helllo ----> Heo
aAaaaA ZZz ---->
EDIT:
In above program, I have used tolower() with an assumption that the string, passed as argument to remove_all_consecutive_dup_chars(), will contain only alphabets - [A - Z]/[a - z] and space character.
Note that, tolower() can result in UB if pstr[i] < 0. If you use tolower(), just make sure that argument you pass to tolower() shall be representable as an unsigned char.
I want to get from user multiple line strings.
How I can do that?
User doesn’t know beforehand how many “paragraphs” wants.
User Input (example_1):
Hello! (clicks Enter button)
World! (clicks Enter button)
(clicks Enter button)
Output:
Hello!
World!
User Input (example_2):
(clicks Enter button)
Output:
(nothing)
There are some notes here:
1. You could have used getline() function instead of scanning characters one by one.
2. Assuming that for now we want to use scanf, you might not now the paragraph's length beforehand, so its better to use a linked list of lines in which you allocate memory dynamically. Here is a working example:
#include <stdio.h>
#include <stdlib.h>
typedef struct _line{
char * chars_in_line;
struct _line * next_line;
}line;
void fill_paragraph_lines(line * first_line , int max_size){
first_line->chars_in_line = (char *)malloc(max_size * sizeof(char));
first_line->next_line = NULL;
line * current_line = first_line;
int i;
char aux = '\0';
while(1){
for(i = 0 ; i < max_size ; i++){
if(aux == '\0'){
printf("enter a character: ");
scanf(" %c" , &aux);
}
// if the received character is not '\n' put that in line
if(aux != '\n'){
current_line->chars_in_line[i] = aux;
aux = '\0';
}
// if you receive \n as an input character, set the ending \0 and break from for loop
else{
current_line->chars_in_line[i] = '\0';
aux = '\0';
break;
}
// reset aux character to its initial value
aux = '\0';
// if you reach max_size also end the string with '\0', no matter what character you received from user
if(i == max_size - 1){
current_line->chars_in_line[i] = '\0';
printf("\nmax line characters reached\n");
aux = '\0';
}
}
// the user can end a paragraph by inputting \n, when previous line is completed
char possible_paragraph_ending;
printf("enter a character: ");
scanf(" %c" , &aux);
if(aux == '\n')
return;
// if the user inputs another character, start a new line
line * new_line = (line*)malloc(sizeof(line));
new_line -> chars_in_line = (char *)malloc(max_size * sizeof(char));
new_line ->next_line = NULL ;
// chain the new line to the previous lines and move the pointer current line to the
// newly created line
current_line->next_line = new_line;
current_line = new_line;
}
}
void destroy_paragraph(line * first_line){
if(first_line == NULL)
return ;
line * traverse_line = (line *)first_line->next_line;
line * dealloc_line = first_line;
while(1){
free(dealloc_line->chars_in_line);
free(dealloc_line);
if(traverse_line == NULL)
return;
dealloc_line = traverse_line;
traverse_line = dealloc_line->next_line;
}
}
void print_paragraph(line * first_line){
line * traverse_line = first_line;
while(traverse_line != NULL){
printf("%s\n" , traverse_line->chars_in_line);
traverse_line = traverse_line->next_line;
}
}
int main() {
line * first_line = (line *)malloc(sizeof(line));
fill_paragraph_lines(first_line , 10) ;
print_paragraph(first_line);
destroy_paragraph(first_line);
return 0 ;
}
In the code above, you need to hit enter after each character in a line. If you want to end a line, you have to press Return 2 times consecutively and you need to press Return 3 times to end a paragraph.
When a new line needs to be generated, memory is dynamically allocated. destroy_paragraph() needs to be called to free memory.
This code does what you are expected to do. I simplified the signature of the function get_string (not sure if the signature you provided was required or not). To the function we pass the array paragraphs (for proof of concept I am using an array with 300 positions, however if you should use malloc and realloc to adjust the size as needed) and the number of strings read in the function.
NOTE: Updated code to count words per paragraph in array as requested by OP.
#include <stdio.h>
#include <string.h>
void get_string(char *paragraphs, int *n) {
char aux[30], i = 0, parg_cur_length = 0;
do{
fgets(aux, sizeof(aux), stdin);
if(aux[0] == '\n')
break;
for(i=0; i< strlen(aux); i++){
paragraphs[parg_cur_length + i] = aux[i];
}
parg_cur_length += strlen(aux);
paragraphs[parg_cur_length] = '\0';
parg_cur_length++;
(*n)++;
}while(aux[0] != '\n');
}
int main()
{
char paragraphs[300];
char * iter_paragraphs = paragraphs;
int n_times = 0, n_chars = 0;
get_string(paragraphs, &n_times);
// let's print what we have
for(int i = 0; i< n_times; i++) {
n_chars = printf("%s", iter_paragraphs);
iter_paragraphs += n_chars+1;
}
// reset pointer
iter_paragraphs = ¶graphs[0];
// let's counts the words per paragraph
int j = 0, word_cnt = 0;
for(int i = 0; i< n_times; i++) {
while(*(iter_paragraphs + j) != '\0') {
if( *(iter_paragraphs + j) == ' ')
word_cnt++;
j++;
}
// assuming last word does not have space but \n instead
n_chars = printf("paragraph %d has %d words\n", i+1, word_cnt+1);
word_cnt = 0;
// move to next pos in array due to \0
j++;
}
}
Nevertheless, IMO a cleaner approach for this would be to use a matrix (char **) as user3121023 suggested.
I'm having trouble with trying to manipulate 2d dynamic arrays in C. What I want to do is to store a char string in every row of the the 2d array then perform a check to see if the string contains a certain character, if so remove all occurrences then shift over the empty positions. What's actually happening is I get an exit status 1.
More about the problem, for example if I have
Enter string 1: testing
Enter string 2: apple
Enter string 3: banana
I would want the output to become
What letter? a // ask what character to search for and remove all occurences
testing
pple
bnn
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
void removeOccurences2(char** letters, int strs, int size, char letter){
// Get size of array
// Shift amount says how many of the letter that we have removed so far.
int shiftAmt = 0;
// Shift array says how much we should shift each element at the end
int shiftArray[strs][size];
// The first loop to remove letters and put things the shift amount in the array
int i,j;
for(i=0;i < strs; i++){
for(j = 0; j < size - 1; j++) {
if (letters[i][j] == '\0'){
break;
}
else {
// If the letter matches
if(letter == letters[i][j]){
// Set to null terminator
letters[i][j] = '\0';
// Increase Shift amount
shiftAmt++;
// Set shift amount for this position to be 0
shiftArray[i][j] = 0;
}else{
// Set the shift amount for this letter to be equal to the current shift amount
shiftArray[i][j] = shiftAmt;
}
}
}
}
// Loop back through and shift each index the required amount
for(i = 0; i < strs; i++){
for(j = 0; j < size - 1; j++) {
// If the shift amount for this index is 0 don't do anything
if(shiftArray[i][j] == 0) continue;
// Otherwise swap
letters[i][j - shiftArray[i][j]] = letters[i][j];
letters[i][j] = '\0';
}
//now print the new string
printf("%s", letters[i]);
}
return;
}
int main() {
int strs;
char** array2;
int size;
int cnt;
int c;
char letter;
printf("How many strings do you want to enter?\n");
scanf("%d", &strs);
printf("What is the max size of the strings?\n");
scanf("%d", &size);
array2 = malloc(sizeof(char*)*strs);
cnt = 0;
while (cnt < strs) {
c = 0;
printf("Enter string %d:\n", cnt + 1);
array2[cnt] = malloc(sizeof(char)*size);
scanf("%s", array2[cnt]);
cnt += 1;
}
printf("What letter?\n");
scanf(" %c", &letter);
removeOccurences2(array2,strs,size,letter);
}
Thanks in advance!
You can remove letters from a string in place, because you can only shorten the string.
The code could simply be:
void removeOccurences2(char** letters, int strs, int size, char letter){
int i,j,k;
// loop over the array of strings
for(i=0;i < strs; i++){
// loop per string
for(j = 0, k=0; j < size; j++) {
// stop on the first null character
if (letters[i][j] == '\0'){
letters[i][k] = 0;
break;
}
// If the letter does not match, keep the letter
if(letter != letters[i][j]){
letters[i][k++] = letters[i][j];
}
}
//now print the new string
printf("%s\n", letters[i]);
}
return;
}
But you should free all the allocated arrays before returning to environment, and explicitely return 0 at the end of main.
Well, there are several issues on your program, basically you are getting segmentation fault error because you are accessing invalid memory which isn't allocated by your program. Here are some issues I found:
shiftAmt isn't reset after processing/checking each string which lead to incorrect value of shiftArray.
Values of shiftArray only set as expected for length of string but after that (values from from length of each string to size) are random numbers.
The logic to delete occurrence character is incorrect - you need to shift the whole string after the occurrence character to the left not just manipulating a single character like what you are doing.
1 & 2 cause the segmentation fault error (crash the program) because it causes this line letters[i][j - shiftArray[i][j]] = letters[i][j]; access to unexpected memory. You can take a look at my edited version of your removeOccurences2 method for reference:
int removeOccurences2(char* string, char letter) {
if(!string) return -1;
int i = 0;
while (*(string+i) != '\0') {
if (*(string+i) == letter) {
memmove(string + i, string + i + 1, strlen(string + i + 1));
string[strlen(string) - 1] = '\0'; // delete last character
}
i++;
}
return 0;
}
It's just an example and there is still some flaw in its logics waiting for you to complete. Hint: try the case: "bananaaaa123"
Happy coding!
"...if the string contains a certain character, if so remove all occurrences then shift over the empty positions."
The original string can be edited in place by incrementing two pointers initially containing the same content. The following illustrates.:
void remove_all_chars(char* str, char c)
{
char *pr = str://pointer read
char *pw = str;//pointer write
while(*pr)
{
*pw = *pr++;
pw += (*pw != c);//increment pw only if current position == c
}
*pw = '\0';//terminate to mark last position of modified string
}
This is the cleanest, simplest form I have seen for doing this task. Credit goes to this answer.
There are some comments in the code for human-readable code:
#include <stdio.h>
#include <string.h>
#define SIZE 100 //size of the input array and output array
#define ACCUM_CHAR_SIZE 25 //size of the temp array
int main(){
char i[SIZE];
char acc[ACCUM_CHAR_SIZE];
char o[SIZE];
int it_l = 0, it_a = 0, it_r = 0;
//it_l is the iterator to the input sentence,
//it_a is the iterator to the temp array
//it_r is the iterator to the output sentence
printf("Enter a sentence:");
gets(i);
int len = strlen(i) - 1;
while(it_l <= len){
if(i[len - it_l] != ' '){
acc[it_a] = i[len - it_l]; //add letters to acc until space
it_a++;
}
else{
it_a -= 1;
//acc is reversed, I reversed it again to the output sentence
while(it_a >= 0){
o[it_r] = acc[it_a];
it_r++;
it_a--;
}
it_r += 1;
o[it_r] = 32; //put a space
it_a = 0; //reset the temp array
strcpy(acc, ""); //clear the acc
}
it_l++;
}
printf("%s", o);
}
The program theoretically looks fine, but when it is executed, it sometimes print garbage values, only some words, or sentence which has only reversed half with garbage value instead of spaces.
The program above is to save each word to the temp, and reverse temp (temp is reversed when storing the word) back to the output. However, it fails.
Thank you for your help.
#include <stdio.h>
#include <string.h>
#define SIZE 100 //The size of input array is prefered to be equal to ouput array.
int main(){
char input[SIZE];
char output[SIZE];
int i = 0, j = 0;
//i is the iterator to the input sentence,
//j is the iterator to the output sentence
printf("Enter a sentence:");
gets(input);
int len = strlen(input) - 1; //Total length.
j = len;
while(input[i]!= NULL){
output[j] = input[i];
i++;
j--;
}
output[len+1]= NULL;
printf("%s", output);
printf("Finished");
}
There are at least three problems.
The first problem is that you never terminate the string o To do that change:
printf("%s", o);
into
o[it_r] = '\0';
printf("%s", o);
The second problem is that you increment it_r incorrectly. Change
it_r += 1;
o[it_r] = 32; //put a space
into
o[it_r] = ' '; // Use ' ' instead of 32
it_r += 1;
The third problem is that you don't handle the first word of the input (because there is no space in front). I'll leave that problem to you as an exercise.
BTW: Don't use gets for reading input. Use fgets instead.
Try the modified code given below, the changed sections has been commented(all other comments were removed for readability)
#include <stdio.h>
#include <string.h>
#define SIZE 100
#define ACCUM_CHAR_SIZE 25
int main(){
char i[SIZE];
char acc[ACCUM_CHAR_SIZE];
char o[SIZE];
int it_l = 0, it_a = 0, it_r = 0;
printf("Enter a sentence:");
gets(i);
int len = strlen(i) - 1;
while(it_l <= len){
if(i[len - it_l] != ' '){
acc[it_a] = i[len - it_l];
it_a++;
}
else{
it_a -= 1;
while(it_a >= 0){
o[it_r] = acc[it_a];
it_r++;
it_a--;
}
/*it_r += 1; There is no need to increment it_r here as
it is already incremented in the above loop*/
o[it_r] = 32;
it_r += 1; /* The above increment statement was moved here(only
incremented when a new value is loaded in to output array) */
it_a = 0;
strcpy(acc, "");
}
it_l++;
}
/* The below section reverses and stores the first word of the
input which was not getting operated in the above loop */
it_a -= 1;
while(it_a >= 0){
o[it_r] = acc[it_a];
it_r++;
it_a--;
}
o[it_r] = '\0'; // Terminating output array
printf("%s", o);
}
The above code will work as expected but has some small issues(given below)
Using gets():- gets is not recommended for inputting strings. See this link for more info.
The Size of temporary array acc :- If a word greater than 25 characters is inputted the program may output garbage value.
Version without temporary storage.
read the input string from start (0)
copy any word from input into output, starting from the end of output - words are not reversed
copy any space in output, from position in output, starting from the end
Code
#define SIZE 100 //size of the input array and output array
int main(){
char i[SIZE];
char o[SIZE];
printf("Enter a sentence: ");
fgets(i, SIZE, stdin); // fgets instead of gets
int j,len = strlen(i) - 1; // assuming you eat the EOL character
o[len] = '\0'; // start by marking end of output string
for(j=0 ; j<len ; j++) { // navigating the input string
if (i[j] == ' ') {
o[len-j-1] = i[j]; // if space, copy (from end) in output
}
else {
int k=j;
do {
k++; // count(+1) the word, non-space, characters
} while (k<len && i[k] != ' ');
strncpy(&o[len-k], &i[j], k-j); // copy the word
j = k-1;
}
}
printf("%s\n", o);
}
I am writing C program that reads input from the standard input a line of characters.Then output the line of characters in reverse order.
it doesn't print reversed array, instead it prints the regular array.
Can anyone help me?
What am I doing wrong?
main()
{
int count;
int MAX_SIZE = 20;
char c;
char arr[MAX_SIZE];
char revArr[MAX_SIZE];
while(c != EOF)
{
count = 0;
c = getchar();
arr[count++] = c;
getReverse(revArr, arr);
printf("%s", revArr);
if (c == '\n')
{
printf("\n");
count = 0;
}
}
}
void getReverse(char dest[], char src[])
{
int i, j, n = sizeof(src);
for (i = n - 1, j = 0; i >= 0; i--)
{
j = 0;
dest[j] = src[i];
j++;
}
}
You have quite a few problems in there. The first is that there is no prototype in scope for getReverse() when you use it in main(). You should either provide a prototype or just move getReverse() to above main() so that main() knows about it.
The second is the fact that you're trying to reverse the string after every character being entered, and that your input method is not quite right (it checks an indeterminate c before ever getting a character). It would be better as something like this:
count = 0;
c = getchar();
while (c != EOF) {
arr[count++] = c;
c = getchar();
}
arr[count] = '\0';
That will get you a proper C string albeit one with a newline on the end, and even possibly a multi-line string, which doesn't match your specs ("reads input from the standard input a line of characters"). If you want a newline or file-end to terminate input, you can use this instead:
count = 0;
c = getchar();
while ((c != '\n') && (c != EOF)) {
arr[count++] = c;
c = getchar();
}
arr[count] = '\0';
And, on top of that, c should actually be an int, not a char, because it has to be able to store every possible character plus the EOF marker.
Your getReverse() function also has problems, mainly due to the fact it's not putting an end-string marker at the end of the array but also because it uses the wrong size (sizeof rather than strlen) and because it appears to re-initialise j every time through the loop. In any case, it can be greatly simplified:
void getReverse (char *dest, char *src) {
int i = strlen(src) - 1, j = 0;
while (i >= 0) {
dest[j] = src[i];
j++;
i--;
}
dest[j] = '\0';
}
or, once you're a proficient coder:
void getReverse (char *dest, char *src) {
int i = strlen(src) - 1, j = 0;
while (i >= 0)
dest[j++] = src[i--];
dest[j] = '\0';
}
If you need a main program which gives you reversed characters for each line, you can do that with something like this:
int main (void) {
int count;
int MAX_SIZE = 20;
int c;
char arr[MAX_SIZE];
char revArr[MAX_SIZE];
c = getchar();
count = 0;
while(c != EOF) {
if (c != '\n') {
arr[count++] = c;
c = getchar();
continue;
}
arr[count] = '\0';
getReverse(revArr, arr);
printf("'%s' => '%s'\n", arr, revArr);
count = 0;
c = getchar();
}
return 0;
}
which, on a sample run, shows:
pax> ./testprog
hello
'hello' => 'olleh'
goodbye
'goodbye' => 'eybdoog'
a man a plan a canal panama
'a man a plan a canal panama' => 'amanap lanac a nalp a nam a'
Your 'count' variable goes to 0 every time the while loop runs.
Count is initialised to 0 everytime the loop is entered
you are sending the array with each character for reversal which is not a very bright thing to do but won't create problems. Rather, first store all the characters in the array and send it once to the getreverse function after the array is complete.
sizeof(src) will not give the number of characters. How about you send i after the loop was terminated in main as a parameter too. Ofcourse there are many ways and various function but since it seems like you are in the initial stages, you can try up strlen and other such functions.
you have initialised j to 0 in the for loop but again, specifying it INSIDE the loop will initialise the value everytime its run from the top hence j ends up not incrmenting. So remore the j=0 and i=0 from INSIDE the loop since you only need to get it initialised once.
check this out
#include <stdio.h>
#include <ctype.h>
void getReverse(char dest[], char src[], int count);
int main()
{
// *always* initialize variables
int count = 0;
const int MaxLen = 20; // max length string, leave upper case names for MACROS
const int MaxSize = MaxLen + 1; // add one for ending \0
int c = '\0';
char arr[MaxSize] = {0};
char revArr[MaxSize] = {0};
// first collect characters to be reversed
// note that input is buffered so user could enter more than MAX_SIZE
do
{
c = fgetc(stdin);
if ( c != EOF && (isalpha(c) || isdigit(c))) // only consider "proper" characters
{
arr[count++] = (char)c;
}
}
while(c != EOF && c != '\n' && count < MaxLen); // EOF or Newline or MaxLen
getReverse( revArr, arr, count );
printf("%s\n", revArr);
return 0;
}
void getReverse(char dest[], char src[], int count)
{
int i = count - 1;
int j = 0;
while ( i > -1 )
{
dest[j++] = src[i--];
}
}
Dealing with strings is a rich source of bugs in C, because even simple operations like copying and modifying require thinking about issues of allocation and storage. This problem though can be simplified considerably by thinking of the input and output not as strings but as streams of characters, and relying on recursion and local storage to handle all allocation.
The following is a complete program that will read one line of standard input and print its reverse to standard output, with the length of the input limited only by the growth of the stack:
int florb (int c) { return c == '\n' ? c : putchar(florb(getchar())), c; }
main() { florb('-'); }
..or check this
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
char *my_rev(const char *source);
int main(void)
{
char *stringA;
stringA = malloc(MAX); /* memory allocation for 100 characters */
if(stringA == NULL) /* if malloc returns NULL error msg is printed and program exits */
{
fprintf(stdout, "Out of memory error\n");
exit(1);
}
else
{
fprintf(stdout, "Type a string:\n");
fgets(stringA, MAX, stdin);
my_rev(stringA);
}
return 0;
}
char *my_rev(const char *source) /* const makes sure that function does not modify the value pointed to by source pointer */
{
int len = 0; /* first function calculates the length of the string */
while(*source != '\n') /* fgets preserves terminating newline, that's why \n is used instead of \0 */
{
len++;
*source++;
}
len--; /* length calculation includes newline, so length is subtracted by one */
*source--; /* pointer moved to point to last character instead of \n */
int b;
for(b = len; b >= 0; b--) /* for loop prints string in reverse order */
{
fprintf(stdout, "%c", *source);
len--;
*source--;
}
return;
}
Output looks like this:
Type a string:
writing about C programming
gnimmargorp C tuoba gnitirw