This program is supposed to dynamically store each string entered into a pointer. Each pointer is part of an array of pointers that will collectively hold all of the strings. When the user enter an empty word, or NULL, it is supposed to quit. My problem is that the code just skips over the NULL conditional statement. I saw some similar posts and have been at it for hours but just can't solve it.
#include <stdio.h>
#include <string.h>
void readWord(char wordChar[], int MAX_CHARS);
int main()
{
int MAX_CHARS = 20;
int wCount = 0;
char *wordArray[wCount]; // Array of pointers that will each point to wordChar
char wordChar[MAX_CHARS];
int i;
for(i = 0;;i++)
{
wCount++;
printf("Enter word: ");
readWord(wordChar, MAX_CHARS); //Reads one word at a time
//Dynamically store each
wordArray[i] = (char*) malloc((int) strlen(wordChar) * (int) sizeof(char));
wordArray[i] = wordChar;
printf("%s \n", wordArray[i]); //Troubleshooting *********************
// If loop ends scanning when word is NULL
if(wordArray[i] == 'NULL')
{
printf("if loop");
break;
}
else printf("no loop");
}
}
/***********************************************************/
void readWord(char wordChar[], int MAX_CHARS)
{
int letter, i = 0;
while((letter = getchar()) != '\n')
{
if(i < MAX_CHARS)
{
wordChar[i] = letter;
i++;
}
}
wordChar[i] = '\0';
}
The short and useless summary is: you're #includeing string.h; use it!
You're trying to compare two pointers directly.
if(wordArray[i] == 'NULL')
This line looks at the pointer value of wordArray[i] to the value of the multi-character literal 'NULL' (note that I didn't say string: you used single quotes here, so 'NULL' has the integer value 0x4e554c4c; see https://stackoverflow.com/a/7459943/510299). If wordArray[i] points to the address 0x12345678, then this is comparing 0x12345678 to 0x4e554c4c and sees that they're not equal.
What you want is to compare strings. In C, you can't do this with == because C strings are char arrays or pointers to chars; == compares the pointer (address) value, as I noted above.
Solution, use strcmp.
if(strcmp(wordArray[i], "NULL") == 0)
(Note the use of double quotes.)
EDIT: Also note that char *wordArray[wCount]; is declared when wCount == 0. This nominally means you tried to declare an array of length 0, which is undefined behaviour. You need to declare wordArray with some length (probably the maximum number of words you can store). [Thanks to riodoro1 for pointing this out in a comment.]
You made a similar blunder with string manipulation in C here:
wordArray[i] = (char*) malloc((int) strlen(wordChar) * (int) sizeof(char));
This line sets the pointer wordArray[i] to some newly allocated memory.
wordArray[i] = wordChar;
This line then proceeds to change the pointer wordArray[i] to point to the original location where the read word was stored. Oops. The next time you go through this loop, wordChar changes, and wordArray[i] is pointing to wordChar... so the new word "replaces" all the previous words.
Solution? You need to copy the string to the memory you just malloc'd. Use strcpy().
printf("if loop");
A conditional (if) statement is not a kind of loop.
#include <stdio.h>
#include <stdlib.h> //for realloc and free (malloc)
#include <string.h>
void readWord(char wordChar[], int MAX_CHARS);
int main(void){
int MAX_CHARS = 20;
int wCount = 0;
char **wordArray = NULL; // Array of pointers that will each point to wordChar
char wordChar[MAX_CHARS];
int i;
for(i = 0;;i++){
printf("Enter word: ");
readWord(wordChar, MAX_CHARS); //Reads one word at a time
if(*wordChar == '\0' || strcmp(wordChar, "NULL") == 0){//empty word or "NULL"
putchar('\n');
break;
}
wCount++;
wordArray = realloc(wordArray, wCount * sizeof(*wordArray));//check omitted
//Dynamically store each
wordArray[i] = malloc(strlen(wordChar) + 1);//+1 for NUL
strcpy(wordArray[i], wordChar);//copy string
}
//check print and free
for(i = 0; i < wCount; ++i){
printf("'%s'\n", wordArray[i]);
free(wordArray[i]);
}
free(wordArray);
return 0;
}
void readWord(char wordChar[], int MAX_CHARS){
int letter, i = 0;
while((letter = getchar()) != '\n' && letter != EOF){
if(i < MAX_CHARS -1)//-1 for NUL, or char wordChar[MAX_CHARS+1];
wordChar[i++] = letter;
else
;//drop letter upto newline
}
wordChar[i] = '\0';
}
Related
This is for Homework
I have to write a program that asks the user to enter a string, then my program would separate the even and odd values from the entered string. Here is my program.
#include <stdio.h>
#include <string.h>
int main(void) {
char *str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s", &str);
while (&str[i] < 41) {
if (i % 2 == 0) {
odd[j++] = *str[i];
} else {
even[k++] = *str[i];
}
i++;
}
printf("The even string is:%s\n ", even);
printf("The odd string is:%s\n ", odd);
return 0;
}
When I try and compile my program I get two warnings:
For my scanf I get "format '%s' expects arguments of type char but argument has 'char * (*)[41]". I'm not sure what this means but I assume it's because of the array initialization.
On the while loop it gives me the warning that says comparison between pointer and integer. I'm not sure what that means either and I thought it was legal in C to make that comparison.
When I compile the program, I get random characters for both the even and odd string.
Any help would be appreciated!
this declaration is wrong:
char *str[41];
you're declaring 41 uninitialized strings. You want:
char str[41];
then, scanf("%40s" , str);, no & and limit the input size (safety)
then the loop (where your while (str[i]<41) is wrong, it probably ends at once since letters start at 65 (ascii code for "A"). You wanted to test i against 41 but test str[i] against \0 instead, else you get all the garbage after nul-termination char in one of odd or even strings if the string is not exactly 40 bytes long)
while (str[i]) {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
if you want to use a pointer (assignement requirement), just define str as before:
char str[41];
scan the input value on it as indicated above, then point on it:
char *p = str;
And now that you defined a pointer on a buffer, if you're required to use deference instead of index access you can do:
while (*p) { // test end of string termination
if (i % 2 == 0) { // if ((p-str) % 2 == 0) { would allow to get rid of i
odd[j++] = *p;
} else {
even[k++] = *p;
}
p++;
i++;
}
(we have to increase i for the even/odd test, or we would have to test p-str evenness)
aaaand last classical mistake (thanks to last-minute comments), even & odd aren't null terminated so the risk of getting garbage at the end when printing them, you need:
even[k] = odd[j] = '\0';
(as another answer states, check the concept of even & odd, the expected result may be the other way round)
There are multiple problems in your code:
You define an array of pointers char *str[41], not an array of char.
You should pass the array to scanf instead of its address: When passed to a function, an array decays into a pointer to its first element.
You should limit the number of characters read by scanf.
You should iterate until the end of the string, not on all elements of the array, especially with (&str[i] < 41) that compares the address of the ith element with the value 41, which is meaningless. The end of the string is the null terminator which can be tested with (str[i] != '\0').
You should read the characters from str with str[i].
You should null terminate the even and odd arrays.
Here is a modified version:
#include <stdio.h>
int main(void) {
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
if (scanf("%40s", str) != 1)
return 1;
while (str[i] != '\0') {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = even[k] = '\0';
printf("The even string is: %s\n", even);
printf("The odd string is: %s\n", odd);
return 0;
}
Note that your interpretation of even and odd characters assumes 1-based offsets, ie: the first character is an odd character. This is not consistent with the C approach where an even characters would be interpreted as having en even offset from the beginning of the string, starting at 0.
Many answers all ready point out the original code`s problems.
Below are some ideas to reduce memory usage as the 2 arrays odd[], even[] are not needed.
As the "even" characters are seen, print them out.
As the "odd" characters are seen, move them to the first part of the array.
Alternative print: If code used "%.*s", the array does not need a null character termination.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[41];
printf("Enter a string (40 characters maximum): ");
fflush(stdout);
if (scanf("%40s", str) == 1) {
int i;
printf("The even string is:");
for (i = 0; str[i]; i++) {
if (i % 2 == 0) {
str[i / 2] = str[i]; // copy character to an earlier part of `str[]`
} else {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:%.*s\n ", (i + 1) / 2, str);
}
return 0;
}
or simply
printf("The even string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 != 0) {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 == 0) {
putchar(str[i]);
}
}
printf("\n");
here is your solution :)
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s" , str);
while (i < strlen(str))
{
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = '\0';
even[k] = '\0';
printf("The even string is:%s\n " , even);
printf("The odd string is:%s\n " , odd);
return 0;
}
solved the mistake in the declaration, the scanning string value, condition of the while loop and assignment of element of array. :)
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]);
i want to type a sequence of chars and save them with a temporary array. After that, i want to create the actual array with a certain size with the values of the temporary array. Here is the code:
#include <stdio.h>
int main()
{
char c;
char temp[100];
char array[24];
int i;
char *ptrtemp = temp;
// create a temporary array with getchar function
while(1) {
c = getchar();
if(c == '\n')
break;
*ptrtemp = c;
i++;
ptrtemp++;
}
// type wrong in case of wrong size
if(i != 24) {
printf("Data is wrong");
exit(0);
}
char *ptrarray = array;
char *ptrtemp2 = temp;
// create the actual array
for(i=0;i<24;i++) {
*ptrarray = *ptrtemp2;
if(i == 23)
break;
ptrarray++;
ptrtemp2++;
}
//printing the actual array
printf("\n%s\n", array);
}
However, I get interesting elements after the actual sequence. The array's size was stated as 24 but 25th, 26th, 27th etc. elements are being also printed.
Here is what I get
Every time I try, I see different extra chars. Can anyone explain what is happening here?
You are doing the stuff far too complicated.
First, as already denoted, i is not initialised. Second, you do not leave space for the terminating 0 in the array. Finally, you can easily write to your array directly:
char array[24 + 1]; // need space for the terminating 0 character
for(int i = 0; i < 24; ++i)
{
// write to array directly:
array[i] = getchar();
if(array[i] == '\n')
{
printf("Data is wrong");
return 0;
}
}
array[24] = 0; // this is important if using %s!
printf("\n%s\n", array);
Actually, you have an alternative, as you know you always want to print exactly 24 characters:
char array[24]; // skipping(!) space for the terminating 0 character
for(int i = 0; i < 24; ++i)
{
// just as above
}
// NOT now (would be UB, as array is too short):
// array[24] = 0;
// but now need to give precision to tell how many bytes to write
// (maximally; if a terminating 0 would be encountered before,
// printf would stop there)
printf("\n%.24s\n", array);
I modified the following:
Initialized i to 0 in the beginning.
memset(temp, 0, sizeof(temp));
Added following to make sure that it does not cross array boundary.
if (i == 99)
{
break;
}
Similarly added following for array variable.
memset(array, 0, sizeof(array));
Following check is done beginning of for loop to make sure it does not write to 24th element of array.
if(i == 23)
break;
#include <stdio.h>
int main()
{
char c;
char temp[100];
char array[24];
int i = 0; //Should be initialized to 0
char *ptrtemp = temp;
memset(temp, 0, sizeof(temp));
// create a temporary array with getchar function
while(1) {
c = getchar();
if(c == '\n')
break;
*ptrtemp = c;
i++;
ptrtemp++;
if (i == 99)
{
break;
}
}
char *ptrarray = array;
char *ptrtemp2 = temp;
memset(array, 0, sizeof(array));
// create the actual array
for(i=0;i<24;i++) {
if(i == 23)
break;
*ptrarray = *ptrtemp2;
ptrarray++;
ptrtemp2++;
}
//printing the actual array
printf("\n%s\n", array);
}
Let me know if you face any problem.
Two problems:
You are using i uninitialized in your code. (I don't think the issue you are seeing is because of that)
All C-strings need to be '\0' terminated. In order to ensure that it is the case, you can always do a:
memset(array, 0, sizeof(array));
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
I have written a C program. It's a character counting program. I will give input as below
Input: ABCAPPPRC
And need as output: A2B1C2P3R1.
But it gives output as A2B1C2A1P3P2P1R1C1. It basically doing as per the logic I have written in program. But I don't want to count the characters of string which have already been counted. Can you suggest what logic I should implement for this?
#include <stdio.h>
int main()
{
char str[30]= "ABCAPPPRC";
char strOutPut[60]="";
char *ptr= &str, *ptr2=&str;
char ch='A';
int count=0;
puts(str);
while (*ptr !=NULL)
{
count =0;
ch = *ptr;
while (*ptr2!= NULL)
{
if (*ptr2 == ch) count++;
ptr2++;
}
printf("%c%d",*ptr, count);
ptr++;
ptr2 = ptr;
}
}
You need to separate the counting from the printing.
The first loop goes through the input and counts the number of occurrences of each character, storing the counts in an array indexed by the character code.
The second loop goes through the array of counts and prints the character corresponding to a non-zero count followed by that count.
For example:
#include <stdio.h>
int main(void)
{
char str[] = "ABCAPPPRC";
int counts[256] = { 0 };
puts(str);
for (char *ptr = str; *ptr != '\0'; ptr++)
counts[(unsigned char)*ptr]++;
for (int i = 0; i < 256; i++)
{
if (counts[i] != 0)
printf("%c%d", i, counts[i]);
}
putchar('\n');
return(0);
}
Sample output:
ABCAPPPRC
A2B1C2P3R1
I could not understand the first for loop. Could you please explain it?
The for control line steps through the string str one character at a time. It is the for loop equivalent of the outer while loop in your original code.
char *ptr = str;
...
while (*ptr != '\0')
{
...
ptr++;
}
The body of the loop converts *ptr (a plain char) into an unsigned char (so that it is guaranteed to be positive), and then uses that value as an index into the array counts. Thus, for example, on the first iteration, A is mapped to 65, and counts[65] is incremented. Thus, for each character code, the loop increments the count corresponding to that character code each time the character is encountered in the string.
The second loop then picks out the non-zero counts, printing the character code as a character followed by its count.
(Incidentally, you should have been getting a compilation warning from the original char *ptr = &str about a type mismatch between char * and char (*)[30]. Learn when to put ampersands in front of array names — you seldom do it unless there is also a subscript after the array name. Thus, &array is usually — but not always — wrong; by contrast, &array[0] is very often valid. Also note that on some machines, NULL is defined as ((void *)0) and this elicits a warning when you compare it to a plain char, as you did with while (*ptr != NULL). You should compare characters to '\0' as in my rewrite; you should reserve NULL for use with pointers.)
str is alerady a character pointer, so when you do this: char *ptr= &str you convert a pointer to pointer to character to a char*. Loose the ampersand(&).
Also in the inner cycle you should check if the given value of ch has already been processed. In the case you use when ptr is pointing to the second A you should just continue, because you have already added the number of A-s in the answer.
Your solution is far from optimal. I strongly suggest you lookup counting sort. It will make your solution faster but also will make it simpler.
# Jonathan your solution is correct only when string characters are given in ascending order like ABCDEF, but it gives problem when character order is changed. Input string is "ABAPPPRCC" and required output is A2B1P3R1C2.
Here in this case your solution will change out put to A2B1C2P3R1.
Below program gives character count without changing string formation.
char *str= "ABAPPPRCC";
char strOutPut[30]="";
char *ptr = str, *ptr2 = str;
char ch='A';
int count=0, i = 0 , total_print = 0;
puts(str);
while (*ptr != '\0')
{
count =0;
ch = *ptr;
while (*ptr2!= '\0')
{
if (*ptr2 == ch) count++;
ptr2++;
}
for( i = 0; i < total_print ; i++ )
{
if ( ch == strOutPut[i] )
{
i = total_print + 1;
break;
}
}
if( i <= total_print )
{
printf("%c%d",*ptr, count);
strOutPut[total_print++] = ch;
}
ptr++;
ptr2 = ptr;
}
#include <stdio.h>
int main(void){
const char noncountchar = '\x11';
char str[30]= "ABCAPPPRC";
char strOutPut[60]="";
char *ptr, *ptr2;
char ch;
int count=0, len=0;
puts(str);
for(ptr=str;ch=*ptr;++ptr){
if(ch == noncountchar) continue;
count =1;
for(ptr2=ptr+1;*ptr2;++ptr2){
if (*ptr2 == ch){
*ptr2 = noncountchar;
++count;
}
}
len += sprintf(strOutPut+len, "%c%d", *ptr, count);
}
printf("%s", strOutPut);
return 0;
}