Peculiar memory/printing issue C - c

#include<stdio.h>
#include<stdlib.h>
#include <string.h>
int main(void){
char dnachar [10]
int cytosine; //first int
int thymine; //second int
int guanine;
int adenine;
printf("Enter DNA Sequence ");
scanf("%10s",dnachar);
printf("dna:%s\n", dnachar);
for (int i = 0; i < 10; i++){
char x = dnachar[i];
if(x == 'c')
cytosine++;
if(x == 't')
thymine++;
if(dnachar[i] == 'g')
guanine++;
if(dnachar[i] == 'a')
adenine++;
}
printf("%d,%d,%d,%d",thymine, guanine, cytosine, adenine);
return 0;
}
Hi, I am new to C and I noticed that the program only prints the first two ints accurately - cytosine and thymine. The others show a random string of incoherent numbers. Why is that and how can I fix it?
edit: I changed i<20 to i<10, I don't know how I made that mistake.

Among the multitude of things wrong in this code
Wrong format limiter
Given:
char dnachar[10];
The code:
scanf("%10s",dnachar);
will read a string up to 10 characters long, not including the terminating null, which it will always place. Therefore, that scanf can write as many as eleven (11) chars in a space only declared to hold ten (10). The result of a ten character string read (or longer) will be undefined behavior.
Solution:
if (scanf("%9s", dnachar) != 1)
return EXIT_FAILURE;
Note: if your sequences are really ten characters each, then dnachar should be declared as:
char dnachar[11]; // account for 10-chars + terminator
And the format string for scanf should be %10s accordingly.
Indeterminate Counters
All four of your counters are indeterminate. They have no specified initial value as automatic variables, and therefore operations expecting predictable results are unfounded. If they had static linkage (either globals or declared static) they would have default values of 0, but that isn't what your code does.
Solution:
int cytosine = 0;
int thymine = 0;
int guanine = 0;
int adenine = 0;
Incorrect Loop Limit
Given:
for (int i = 0; i < 20; i++){
char x = dnachar[i];
This assumes there are twenty characters in dnachar (which is impossible unless you've invoked undefined behavior from the item above). One you access dnachar[10] and beyond, more undefined behavior. Ideally you stop processing chars when there are no more, which is much easier with a pointer than an index.
Solution:
for (char *p = dnachar; *p; ++p)
{
switch(*p)
{
case 'c':
++cytosine;
break;
case 't':
++thymine;
break;
case 'g':
++guanine;
break;
case 'a':
++adenine;
break;
default:
break;
}
}

Related

Hello i got an assignment in c programing and i dont really understand the c/malloc function i think

Hello i got an assignment in c programing and i dont really understand the c/malloc function i think,
they told us that we need to do the free function after using this function, but every time i do free it breaks the program
The assignment is :
collect an input string.
every upper case letter to lower
every lower case letter to upper
if there is number do series of numbers from '9' until the input number but with out it (for '6' do '9','8','7'. (with out 6))
if there is other stuff don't add it in to the out put.
input example : A$q6#G4
output example : aQ987g98765
it is not allowed to change the input string.
in the input allowed to be every thing.
the output sting needs to be exactly in the array size
(if 123 = the size of will be input[2])
photo of the error
the error : wntdll.pdb contains the debug information required to find the source for the module ntdll.dll
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
/* Function declarations */
char Ex1FNumbers(char);
char Ex1FLetters(char);
/* ------------------------------- */
//
int main()
{
system("cls"); //delete when send
int select = 0, i, all_Ex_in_loop = 0;
printf("Run menu once or cyclically?\n(Once - enter 0, cyclically - enter other number) ");
if (scanf_s("%d", &all_Ex_in_loop) == 1)
do
{
for (i = 1; i <= 3; i++)
printf("Ex%d--->%d\n", i, i);
printf("EXIT-->0\n");
do {
select = 0;
printf("please select 0-3 : ");
scanf_s("%d", &select);
} while ((select < 0) || (select > 3));
switch (select)
{
case 1: //Ex1
{
int size, i, n, counter = 0;
char inPut[] = "";
char outPut[] = "";
char* Ptr_inPut_address, * Ptr_outPut_address, num;
printf("Please enter a string :\n");
scanf("%s", inPut);
size = strlen(inPut);
Ptr_outPut_address = &outPut;
Ptr_inPut_address = (char*) calloc(size+1 , sizeof(char));
Ptr_outPut_address = (char*) calloc(0, sizeof(char));
if (!Ptr_inPut_address || !Ptr_outPut_address)
{
break;
}
for (i = 0; i < size; i++)
{
Ptr_outPut_address = (char*)realloc(Ptr_outPut_address, counter);
if (inPut[i] >= 'a' && inPut[i] <= 'z' || inPut[i] >= 'A' && inPut[i] <= 'Z')
{
if (inPut[i] >= 'a' && inPut[i] <= 'z')
{
outPut[counter++] = inPut[i] - 32;
}
else
{
outPut[counter++] = inPut[i] + 32;
}
}
else if (inPut[i] <= '9' && inPut[i] >= '0')
{
n = '9' - inPut[i];
Ptr_outPut_address = (char*)realloc(Ptr_outPut_address, counter + n);
for (n; n > 0; n--) // "o" of 8 and not "n" because 8 is the max num for this "for".
{
outPut[counter++] = inPut[i] + n;
}
}
}
Ptr_outPut_address = (char*)realloc(Ptr_outPut_address, counter);
outPut[counter] = '\0';
Ptr_outPut_address = &outPut;
printf("%s\n", Ptr_outPut_address);
if (Ptr_outPut_address != NULL)
{
free(Ptr_outPut_address);
}
if (Ptr_inPut_address != NULL)
{
free(Ptr_inPut_address);
}
} break;
case 2: //Ex2
{
}break;
case 3: //Ex3
{
}break;
}
} while (all_Ex_in_loop && select);
system("pause");//delete when send
main();//delete when send
//return 0; // return when send
}
char inPut[] = "";
char outPut[] = "";
This declares two arrays that contain exactly one char, initializing them to '\0'. That's what the above means in C. This does not mean that these two arrays will have infinite size and can store any string. That's not how this works. But then, immediately afterwards:
scanf("%s", inPut);
This is guaranteed to overflow the array, since it is capable of holding only one char. Any string this reads will have at least two chars: the single read character, followed by '\0'. This results in memory corruption and undefined behavior.
There are several other bugs in the shown code. One more example:
Ptr_outPut_address = &outPut;
This has the effect of setting this variable to the starting address of a char array that was declared earlier.
Ptr_outPut_address = (char*)realloc(Ptr_outPut_address, counter);
You can only realloc something that was malloced, realloced, or calloced. No exceptions. You cannot realloc anything else. The char array was not malloced, realloced, or calloced. C does not work this way.
Several other problems exists in the shown code. Looks like this entire program was written all at once, before an attempt was made to test everything. This approach is very unlikely to succeed, and will likely produce many different kinds of bugs, such as the one that I've described. This makes it difficult to analyze and fix everything, since you're not looking for just one bug, but an unknown number of bugs. Plus it is likely that there will be an eventual realization that some or most of what was written need to be rewritten from scratch since the shown approach turned out to be fundamentally wrong.
Which is what you should probably do: start from scratch, write only a few lines of code, before testing them, and making sure that they work correctly before proceeding to write more code. If you attempt to fix just the problems that I explained it's likely that this will just create other problems, additionally, there are other problems as well, I just didn't mention them. The entire approach that was used here needs to be changed, fundamentally.

Decimal to binary using string in c....stuck with some conceptual error

#include<stdio.h>
char bin(int);
int main()
{
setbuf(stdout,NULL);
int num;
char res[50];
printf("Enter the number: ");
scanf ("%d",&num);
res=bin(num);
printf("%s",res);
return 0;
}
char bin(int num)
{
char str[50];
int i,val;
for(i=0;num>=0;i++)
{
val=num%2;
str[i]=val;
num=num/2;
}
return str;
}
I really cant understand the error in the usage of strings... to convert the decimal to binary. Whats the conceptual error Im not following?
char is a single character, so char bin(int) will not be able to return a string (i.e. a null-terminated array of characters). And you cannot "return" an an array of characters, because C does not allow to return any array as function result. You can just pass/return pointers to the begin of such arrays.
So I'd suggest to change the interface of bin to reicieve the result buffer as parameter. Don't forget to "close" the string, i.e. to write the string termination character after the last "actual" character:
void bin(int num, char* resultBuffer) {
...
resultBuffer[i] = '\0';
}
In main, you call it then like
bin(num, res);
Returning str amounts to returning a local variable, you can't do it, what you can do is to return a pointer to a previously allocated memory block that works as an array (as an alternative to the oher answer, which is a good solution).
To do this you can declare str as a pointer, allocate memory for it and return it, making sure the variable to which the value is assigned is also a pointer, all the rest can remain the same.
There are, however, problems with the bin function.
Consider the statement:
str[i] = val;
This will not work as expected you are assigning the int result of the operation, which will be 1 or 0, you need to convert this value to the respective character.
The loop for (i = 0; num >= 0; i++) is an infinite loop because num will never be negative, unless you provide it a negative number in which case it will break in the first iteration, that is to say this code only works with positive integers. You need > instead of >=.
Finally you need to null terminate the string when the conversion is complete.
Corrected code (Online):
#include <stdio.h>
#include <stdlib.h>
char *bin(int); //return pointer
int main() {
setbuf(stdout, NULL);
int num;
char *res; //use pointer to receive string assignment
printf("Enter the number: ");
scanf("%d", &num);
res = bin(num);
printf("%s", res);
return 0;
}
char *bin(int num) {
char *str = malloc(50); // allocate memory
int i, val;
for (i = 0; num > 0; i++) { // replacing >= with >
val = num % 2;
str[i] = val + '0'; // convert to character
num = num / 2;
}
str[i] = '\0'; //null terminate the string
return str;
}
Note that you should also check for the inputed value, if it is larger than what an int variable can hold it will result in undefined behavior.

My program doesn't manipulate a string's values correctly

I need to code a program that gets input values for a string, then it ignores the characters that are not digits and it uses the digits from the string to create an integer and display it. here are some strings turned into integers as stated in the exercise.
I wanted to go through the string as through a vector, then test if the each position is a digit using isdigit(s[i]), then put these values in another vector which creates a number using the digits. At the end it's supposed to output the number. I can't for the life of it figure what's wrong, please help.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main()
{
char *s;
scanf("%s", s);
printf("%s\n", s);
int i, n=0, v[100], nr=0;
for(i=0; i<strlen(s); i++)
{
if (isdigit(s[i]) == 1)
{
v[i] = s[i];
n++;
}
}
for(i=0;i<n;i++)
{
printf("%c\n", v[i]);
}
for(i=0; i<n; i++)
{
nr = nr * 10;
nr = nr + v[i];
}
printf("%d", nr);
return 0;
}
The pointer s is unintialized which is your major problem. But there are other problems too.
isdigit() is documented to return a non-zero return code which is not necessarily 1.
The argument to isdigit() needs to be cast to unsigned char to avoid potential undefined behaviour.
Your array v is also using the same index variable i - which is not right. Use a different variable to index v when you store the digits.
You need to subtract '0' to get the each digits integer equivalent.
scanf()'s format %s can't handle inputs with space (among other problems). So, use fgets().
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char s[256];
fgets(s, sizeof s, stdin);
s[strcspn(s, "\n")] = 0; /* remove trailing newline if present */
printf("%s\n", s);
int i, n = 0, v[100], nr = 0;
size_t j = 0;
for(i = 0; i < s[i]; i++)
{
if (isdigit((unsigned char)s[i]))
{
v[j++] = s[i];
n++;
}
}
for(i = 0;i < j; i++)
{
printf("%c\n", v[i]);
}
if (j) { /* No digit was seen */
int multiply = 1;
for(i= j-1 ; i >= 0; i--) {
nr = nr + (v[i] - '0') * multiply;
multiply *= 10;
}
}
printf("%d", nr);
return 0;
}
In addition be aware of integer overflow of nr (and/or multiply) can't hold if your input contains too many digits.
Another potential source of issue is that if you input over 100 digits then it'll overflow the array v, leading to undefined behaviour.
Thanks a lot for your help, i followed someone's advice and replaced
v[i] = s[i] -> v[n] = s[i] and changed char *s with char s[100]
now it works perfectly, i got rid of the variable nr and just output the numbers without separating them through \n . Thanks for the debugger comment too, I didn't know I can use that effectively.
Firstly, you did not allocate any memory, I changed that to a fixed array.
Your use of scanf will stop at the first space (as in the first example input).
Next, you don't use the right array index when writing digits int v[]. However I have removed all that and simply used any digit that occurs.
You did not read the man page for isdigit. It does not return 1 for a digit. It returns a nonzero value so I removed the explicit test and left it as implicit for non-0 result.
I changed the string length and loop types to size_t, moving the multiple strlen calls ouside of the loop.
You have also not seen that digits' character values are not integer values, so I have subtracted '0' to make them so.
Lastly I changed the target type to unsigned since you will ignore any minus sign.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char s[100]; // allocate memory
unsigned nr = 0; // you never check a `-` sign
size_t i, len; // correct types
if(fgets(s, sizeof s, stdin) != NULL) { // scanf stops at `space` in you example
len = strlen(s); // outside of the loop
for(i=0; i<len; i++) {
if(isdigit(s[i])) { // do not test specifically == 1
nr = nr * 10;
nr = nr + s[i] - '0'; // character adjustment
}
}
printf("%u\n", nr); // unsigned
}
return 0;
}
Program session:
a2c3 8*5+=
2385
Just use this
#include <stdio.h>
#include <ctype.h>
int main()
{
int c;
while ((c = getchar()) != EOF) {
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '\n':
putchar(c); break;
}
}
return 0;
} /* main */
This is a sample execution:
$ pru_$$
aspj pjsd psajf pasdjfpaojfdapsjd 2 4 1
241
1089u 0u 309u1309u98u 093u82 40981u2 982u4 09832u4901u 409u 019u019u 0u3 0ue
10890309130998093824098129824098324901409019019030
Very elegant! :)

Program runs too slowly with large input - C

The goal for this program is for it to count the number of instances that two consecutive letters are identical and print this number for every test case. The input can be up to 1,000,000 characters long (thus the size of the char array to hold the input). The website which has the coding challenge on it, however, states that the program times out at a 2s run-time. My question is, how can this program be optimized to process the data faster? Does the issue stem from the large char array?
Also: I get a compiler warning "assignment makes integer from pointer without a cast" for the line str[1000000] = "" What does this mean and how should it be handled instead?
Input:
number of test cases
strings of capital A's and B's
Output:
Number of duplicate letters next to each other for each test case, each on a new line.
Code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
int n, c, a, results[10] = {};
char str[1000000];
scanf("%d", &n);
for (c = 0; c < n; c++) {
str[1000000] = "";
scanf("%s", str);
for (a = 0; a < (strlen(str)-1); a++) {
if (str[a] == str[a+1]) { results[c] += 1; }
}
}
for (c = 0; c < n; c++) {
printf("%d\n", results[c]);
}
return 0;
}
You don't need the line
str[1000000] = "";
scanf() adds a null terminator when it parses the input and writes it to str. This line is also writing beyond the end of the array, since the last element of the array is str[999999].
The reason you're getting the warning is because the type of str[10000000] is char, but the type of a string literal is char*.
To speed up the program, take the call to strlen() out of the loop.
size_t len = strlen(str)-1;
for (a = 0; a < len; a++) {
...
}
str[1000000] = "";
This does not do what you think it does and you're overflowing the buffer which results in undefined behaviour. An indexer's range is from 0 - sizeof(str) EXCLUSIVE. So you either add one to the
1000000 when initializing or use 999999 to access it instead. To get rid of the compiler warning and produce cleaner code use:
str[1000000] = '\0';
Or
str[999999] = '\0';
Depending on what you did to fix it.
As to optimizing, you should look at the assembly and go from there.
count the number of instances that two consecutive letters are identical and print this number for every test case
For efficiency, code needs a new approach as suggeted by #john bollinger & #molbdnilo
void ReportPairs(const char *str, size_t n) {
int previous = EOF;
unsigned long repeat = 0;
for (size_t i=0; i<n; i++) {
int ch = (unsigned char) str[i];
if (isalpha(ch) && ch == previous) {
repeat++;
}
previous = ch;
}
printf("Pair count %lu\n", repeat);
}
char *testcase1 = "test1122a33";
ReportPairs(testcase1, strlen(testcase1));
or directly from input and "each test case, each on a new line."
int ReportPairs2(FILE *inf) {
int previous = EOF;
unsigned long repeat = 0;
int ch;
for ((ch = fgetc(inf)) != '\n') {
if (ch == EOF) return ch;
if (isalpha(ch) && ch == previous) {
repeat++;
}
previous = ch;
}
printf("Pair count %lu\n", repeat);
return ch;
}
while (ReportPairs2(stdin) != EOF);
Unclear how OP wants to count "AAAA" as 2 or 3. This code counts it as 3.
One way to dramatically improve the run-time for your code is to limit the number of times you read from stdin. (basically process input in bigger chunks). You can do this a number of way, but probably one of the most efficient would be with fread. Even reading in 8-byte chunks can provide a big improvement over reading a character at a time. One example of such an implementation considering capital letters [A-Z] only would be:
#include <stdio.h>
#define RSIZE 8
int main (void) {
char qword[RSIZE] = {0};
char last = 0;
size_t i = 0;
size_t nchr = 0;
size_t dcount = 0;
/* read up to 8-bytes at a time */
while ((nchr = fread (qword, sizeof *qword, RSIZE, stdin)))
{ /* compare each byte to byte before */
for (i = 1; i < nchr && qword[i] && qword[i] != '\n'; i++)
{ /* if not [A-Z] continue, else compare */
if (qword[i-1] < 'A' || qword[i-1] > 'Z') continue;
if (i == 1 && last == qword[i-1]) dcount++;
if (qword[i-1] == qword[i]) dcount++;
}
last = qword[i-1]; /* save last for comparison w/next */
}
printf ("\n sequential duplicated characters [A-Z] : %zu\n\n",
dcount);
return 0;
}
Output/Time with 868789 chars
$ time ./bin/find_dup_digits <dat/d434839c-d-input-d4340a6.txt
sequential duplicated characters [A-Z] : 434893
real 0m0.024s
user 0m0.017s
sys 0m0.005s
Note: the string was actually a string of '0's and '1's run with a modified test of if (qword[i-1] < '0' || qword[i-1] > '9') continue; rather than the test for [A-Z]...continue, but your results with 'A's and 'B's should be virtually identical. 1000000 would still be significantly under .1 seconds. You can play with the RSIZE value to see if there is any benefit to reading a larger (suggested 'power of 2') size of characters. (note: this counts AAAA as 3) Hope this helps.

Function that counts chars in a string in C

I am new a C. I would like to get help to finish my function.
The mission is:
Write a function that accepts a string maximum length of 256 characters containing characters from 'a' to 'z'.
The function to print the number of occurrences of each character.
For example: input abba output will be:
a = 2 b = 2 c = 0 d = 0 .... z = 0
Do not use if during any function.
I would like to get your help to finish this program please.
This is my code
#include "stdlib.h"
#include "conio.h"
#include "stdio.h"
#include "string.h"
#define size 256
void repeat(char *str);
void main()
{
char str[size];
printf("Please enter a string:\n");
flushall;
gets(str);
repeat(str);
system("pause");
return ;
}
void repeat(char *str)
{
char temp=strlen(str);
int i, count=0;
do
{
for (i=0; i<temp ; i++)
{
count += (*str == str[temp-i]);
}
printf("Char %c appears %d times\n ",*str,count);
count=0;
}
while(*(str++));
}
Please enter a string:
abbba
Char a appears 1 times
Char b appears 2 times
Char b appears 1 times
Char b appears 0 times
Char a appears 0 times
Char appears 0 times
Press any key to continue . . .
this is the output!
I would like to do it in the same building i did.
and should be like
Char a appears 2 times
Chars b appears 3 times
You make a stipulation about not using if. This satisfies that restriction.
#include <stdio.h>
int main(void) {
int i, c;
int counts[256] = { 0 };
const char lower[] = "abcdefghijklmnopqrstuvwxyz";
while ((c = getchar()) != EOF) {
counts[c] += 1;
}
for (i = 0; lower[i]; ++i) {
c = lower[i];
printf("Char %c appears %d times.\n", c, counts[c]);
}
return 0;
}
The problem with your attempt is that you do not track any state to remember which characters you have already printed information about. It also fails to include the character under consideration as part of the count. It also makes multiple passes over the string to collect count information about each character, but that doesn't affect correctness, just performance. If you can somehow remember which character you have already printed out information for, so that you don't do it again when the same character appears later in the string, your method should print out the counts for the characters that appear. Afterwards, you would need to print out zero counts for the characters that did not appear at all. If the outputs need to be in alphabetical order, then you need to make sure you take care of that as well.
One way to track the information properly and to allow your output to be printed in alphabetical order is to maintain counts for each character in an array. After making a pass over the string and incrementing the count associated with each found character, you can iterate over the count array, and print out the counts.
The following program is for zubergu:
#include <stdio.h>
#include <string.h>
int main (void) {
int i, c;
int counts[26] = { 0 };
const char lower[] = "abcdefghijklmnopqrstuvwxyz";
while ((c = getchar()) != EOF) {
switch (c) {
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
counts[strchr(lower, c) - lower] += 1;
break;
default:
break;
}
}
for (i = 0; lower[i]; ++i) {
printf("Char %c appears %d times.\n", lower[i], counts[i]);
}
return 0;
}
It might be one of the ugliest solutions, but also the simplest:
while(*str!='\0')
{
switch(tolower(*str))
{
case 'a': a_count++;break;
case 'b': b_count++;break;
.
.
.
}
str++;
}
It checks if str points to valid letter, then turns it to lower, so it's not case sensitive('A' will be same as 'a' character). No 'if' used and will work with every length char array terminated with '\0' char.
EDIT I have edited the program to follow the requirements of #SagiBinder.
(In my old version, I used an if sentence that checked if the character is in the set 'a'...'z').
The type of temp must be "bigger", that is, something different to char.
Try int, instead.
The algorithm would be this (some details of your program are not repeated here):
int temp = strlen(str);
int i, j;
unsigned char c;
int ch[UCHAR_MAX]; // The macro CHAR_MAX needs the header <limits.h>
for (i = 1; i <= UCHAR_MAX; i++)
ch[i] = 0;
for (j=0; j<temp ; j++) {
c = (unsigned char)(str[j]);
ch[c]++;
}
for (c = 'a'; c <= 'z'; c++)
printf("%c == %d\n", c, ch[c]);
The variable temp holds the length of the string str.
The macro UCHAR_MAX (existing in the header <limits.h>, that you have to #include at the beginning of the program). It is the max. value that holds in a unsigned char.
The array ch[] contains a component for each possible value in the range of the type unsigned char. The intent is that, for some character c, the element ch[c] is the amount of times that c is in str.
I have used unsigned char in order to ensures that the index c of the array ch[] when writting ch[c] is a non-negative integer value, because an array cannot have negative indexes.
The 2nd for goes through the string str. In the step number j, the j-th character of the string str is taken.
This character is a value of type char.
Since one cannot be sure that char have not negative values, I have converted it to (unsigned char) with an explicit cast.
This value is held in the variable c.
The value of c has the (unsigned char version of the) j-th character in str,
so we are going to count it.
How?
Well, we access the array of counters: ch[] with index c, and increment its value in 1:
ch[c]++;
After the for is finished, we have in the array ch[] the information we want.
Finally, we check for the characters from 'a' to 'z'.
(For this, we have supposed that the character encodings in our system follow the convention that the letters have contiguous values).
The 3rd for goes from 'a' to 'z', and the values of the letter (the variable c that controls the for) and the counting of this letter, that is, ch[c].
Moreover: to show the count of any character, you need a re-cast to char, in this way:
printf("%c: %d\n", (char)c, ch[c]);
But this is not necessary with the letters 'a' to 'z', because they belong to the basic execution character set which means that their values are non-negative and equal to their unsigned char counterparts. So, in this case, it is enough to write:
printf("%c: %d\n", c, ch[c]);
EDIT 2: I will use the idea in the answer of #jxh to improve my code.
Since it cannot be guaranted that the encodings of letters 'a' to 'z' are in contiguous order, we can use a string holding the letters:
char letters[] = "abcdefghijklmnopqrstuvwxyz";
The "last" element is, by C convention, a \0 character held after the element 'z'.
Now, we can show the letter counting by changing the 3rd `for` in this way:
for (i = 0; letter[i] != '\0'; i++)
printf("%c == %d\n", letter[i], ch[letter[i]]);
This is equivalent to write:
for (i = 0; letter[i] != '\0'; i++) {
c = letter[i];
printf("%c == %d\n", c, ch[c]);
}
Optimized solution. complexity O(N), N - Input String length.
your void repeat function will be like this,
void repeat(char *str)
{
int temp=strlen(str);// use int here
int i, count=0;
int charCount[26] = {0};
#if 0
//your logic, traverses the string (n*n) time, n - input string length.
do
{
for (i=0; i<temp ; i++)
{
count += (*str == str[temp-i]);
}
printf("Char %c appears %d times\n ",*str,count);
count=0;
}
while(*(str++));
#endif
#if 1
// This logic traverses string once only. n time, n - input string length.
for (i=0; i<temp ; i++)
{
charCount[str[i]%'a']++;
}
for (i=0; i<26 ; i++)
{
printf("%c appears : %d times \n", 'a'+i, charCount[i]);
}
#endif
}
[EDIT]
Here
charCount[str[i]%'a']++; // 'a' is used a its ASCII Value.
You can use it as
charCount[str[i]%97]++;
If you wan to count lower case letter and upper case letter both.
use it like this
if(str[i] >= 'a' && str[i] <= 'z'){
iMap = str[i]%97; // 97 is ASCII Value of 'a'
charCount[iMap]++;
}else if(str[i] >= 'A' && str[i] <= 'Z'){
iMap = str[i]%65; // 65 is ASCII Value of 'A'
charCount[iMap]++;
}
//iMpa is a integer (int iMap;), used for better undersanding.
i = 0;
while (s[i] !=0)
if (( s[i] >= 'a' && s[i] <= 'z') || (s[i] <= 'A' && s[i] >= 'Z'))
{
letters++;
i++;
}
else
if (( s[i] >= '!' && s[i] <= ')'))
{
other++;
}
else
if (( s[i] >= '0' && s[i] <= '9'))
{
numbers++;
}
total = letters + numbers + other;

Resources