String Incrementing Function in C - c

For my programming class, I am trying to write a function incrementstring() that takes the string 'str' passed in from a driver, and adds one to them. It should work with both letters and numbers (ex. '1' goes to '2', 'a' goes to 'b', 'z' goes to 'aa', 'ZZ' goes to 'AAA'). I have almost every test condition working, except for one bug that I can't seem to find a way around.
This is what I currently have:
void incrementstring(char* str){
int i;
int j;
int length = strlen(str);
for(i = strlen(str)-1; i >= 0; i--){
if (str[i] == '9'){
str[i] = '0';
if (str[0] == '0'){
for (j = strlen(str)-1; j>=0; j--){ //This loop is the problem
str[j+1] = str[j];
}
str[0] = '1';
}
}
else if (str[i] == 'z'){
if (str[0] == 'z'){
str[i] = 'a';
str[i+1] = 'a';
}
str[i] = 'a';
}
else if (str[i] == 'Z'){
if(str[0] == 'Z'){
str[i] = 'A';
str[i+1] = 'A';
}
str[i] = 'a';
}
else{
str[i]++;
return;
}
}
}
When I run the function, this is what the driver outputs:
1. testing "1"... = 2. Correct!
2. testing "99"... = 100. Correct!
3. testing "a"... = b. Correct!
4. testing "d"... = e. Correct!
5. testing "z"... = INCORRECT: we got "aa0". We should be getting "aa" instead.
6. testing "aa"... = ab. Correct!
7. testing "Az"... = Ba. Correct!
8. testing "zz"... = aaa. Correct!
9. testing "cw"... = cx. Correct!
10. testing "tab"... = tac. Correct!
11. testing "500"... = 501. Correct!
11 tests run.
I wrote a for loop in line 9 to handle the '99' to '100' condition. It takes every index of the string and shifts it one to the right, and then adds a '1' to the beginning of the string. However, this loop for some reason messes up the 5th test condition, as seen above. If I take the loop out, '99' will go to '00', but the 5th test will pass with no problems. I've hit a brick wall here and I was wondering if anybody can provide some insight.
I appreciate the help, thanks.

While also keeping track of string length to make sure you do not overwrite its allocated space, add a null terminating character to each of your if() and if else segments:
str[0] = '1';
str[1] = 0;
...
str[i] = 'a';
str[i+1] = 0;
And so on.
This final statement may not be doing what you expect it should do.
I believe what you want to do is to increment the expression to point to the next element of memory owned bystr.
Keep in mind that str is actually not an array. It is a pointer. The [...]
notation you are using is a convenience provided in C to allow array like referencing of pointers.
So, the expression str[i] for example can also be expressed as *(str + i).
If it is the next memory location (where the next char is stored)you want, the expression would be:
*(str + i++), which when using array notation translates to: str[i++]
Change the following from
else{
str[i]++;
to:
else{
str[i++]=0;

Your issue is that you're not NULL-terminating your string in the driver program. Running your code with my own driver program works perfectly, so any additional help would require you to share your driver program with us.
All you have to do is, after you fill the char * with the string, make the next character a '\0' character. Since the strlen function simply iterates over the array of chars until it reaches a NULL terminating character, you have to terminate all strings with that character before using them.

Does it work for "zaz" correctly?

Related

Why is the concatenated string at the end totally different from what the code does?

The code below might seem big, but it's really simple. I wanted to make an exercise generator in C, which concatenates latex formatted strings, stored in the function local arrays.
But the output is totally not what I expected it to be. I might have done something wrong with the pointers, or some overflow somewhere.
Tried all the tips I could find on internet:
(1) Initialize a string with '\0' at position 0;
(2) Use a pointer to the string to pass to the function;
int create_exercise_string(char **s, int s_size) {
// The format of the exercise is x+n=m;
// ASCII 48-57 = '0' ... '9';
int exercises_left = 10;
char *exercise;
char operation_list[][2] = {"+\0", "-\0"};
char equal[] = "&=&"; // & is for centering on the item contained in latex;
char array_begin[] = "\\begin{eqnarray*}\n";
char array_end[] = "\\end{eqnarray*}";
char number[1];
strcat(*s, array_begin);
s_size -= strlen(array_begin);
//REMOVE
puts("before exercise generation");
while (exercises_left > 0 && s_size > 0) {
exercise = malloc(256);
if (!exercise) {
puts("allocating error, quitting...");
getchar();
exit(1);
}
exercise[0] = '\0';
// THE INTERESTED PART =================================================
if (exercises_left < 10)
strcat(exercise, "\\\\\n");
printf("exercise number %d\n", exercises_left);
strcpy(exercise, "x");
//add an operator
strcat(exercise, operation_list[rand() % 2]);
// add a number
number[0] = (rand() % 10) + 48;
strcat(exercise, number);
// add an equal
strcat(exercise, equal);
// add a number
number[0] = (rand() % 10) + 48;
strcat(exercise, number);
// END =================================================================
s_size -= strlen(exercise);
strcat(*s, exercise);
free(exercise);
exercises_left--;
}
//REMOVE
puts("exercise generation ended");
if (s_size < strlen(array_end)) {
puts("create_exercise_string: buffer overflow detected, quitting...");
getchar();
exit(1); // for now... will be substituted with proper code
}
else strcat(*s, array_end);
puts("allocation worked, returning in main");
return exercises_left; // 0 if succesfull;
}
I was expecting the output to be like this
\begin{eqnarray*}
x-9&=&3\\
x+3&=&12\\
x-2&=&3\\
... 7 other exercises
\end{eqnarray*}
But I actually get
\begin{eqnarray*}
x-5\end{eqnarray*}&=&9\end{eqnarray*}x-9\end{eqnarray*}&=&2\end{eqnarray*}x+3\end{eqnarray*}&=&1\end{eqnarray*}x-7\end{eqnarray*}&=&0\end{eqnarray*}x+6\end{eqnarray*}&=&1\end{eqnarray*}x-6\end{eqnarray*}&=&5\end{eqnarray*}x+6\end{eqnarray*}&=&8\end{eqnarray*}x-8\end{eqnarray*}&=&6\end{eqnarray*}x+4\end{eqnarray*}&=&5\end{eqnarray*}x+1\end{eqnarray*}&=&5\end{eqnarray*}\end{eqnarray*}
With no \n added overall, and some \end{eqnarray*} repeatedly added...
What is wrong?
I managed to fix it.
All I can say is, when working with strings, always keep in mind if the terminating character is added or not, so in my case, I need to reinforce the study of strings allocation in C.
The problem was the variable number[1].
number[0] = rand() % 10 + 48;
This code adds the char representation of a number between 0 and 9 [48,57] in ASCII.
But it doesn't add a terminating null character!
Everytime I concatenated number to the exercise string, it overflowed to another local variable which had the terminating null character, thus the "undefined behaviour" of strcat() was that it kept reading another local variable.
Lucky me in memory there was a '\0' minefield, otherwise I would have needed to bang my head on the wall, if protected memory was tried to be read.
Thanks for the help!

Can't understand small part of strcmp function

I'm reading a book in C and have seen these two strcmp algorithm.
I have learned my self how the usel for loop works.
But these two for loop are new for me. I don't understand these parts
for (i = 0; s[i] == t[i]; i++)
It have no length instead have this s[i] == t[i].
for ( ; *s == *t; s++, t++) what means this guy ;.
The other parts i understand and I'm also aware what these function returns.
/* strcmp: return <0 if s<t, 0 if s==t, >0 if s>t */
int strcmp(char *s, char *t)
{
int i;
for (i = 0; s[i] == t[i]; i++)
if (s[i] == '\0')
return 0;
return s[i] - t[i];
}
int strcmp(char *s, char *t)
{
for ( ; *s == *t; s++, t++)
if (*s == '\0')
return 0;
return *s - *t;
}
First, some basics.
The syntax of a for loop is
for ( expr1opt ; expr2opt ; expr3opt ) statement
Each of expr1, expr2, and expr3 are optional. The statement
for ( ; ; ) { // do something }
will loop "forever", unless there's a break or return statement somewhere in the body of the loop.
expr1, if present, is evaluated exactly once before loop execution - it's used to establish some initial state (such as setting an index to 0, or assigning a pointer value, or something like that).
expr2, if present, is evaluated before each iteration of the loop body. It's the test condition for continuing loop execution. If the expression evaluates to a non-zero value, the loop body is executed; otherwise, the loop exits. If expr2 is missing, it is assumed to evaluate to 1 (true).
expr3, if present, is evaluated after each iteration of the loop body. It usually updates whatever is being tested in expr2.
for (i = 0; s[i] == t[i]; i++) It have no length instead have this s[i] == t[i]
This loop will execute as long as s[i] == t[i]; as soon as t[i] is not equal to s[i], the loop will exit. By itself, this means the loop will run past the end of the string in case you have identical strings - if both s and t contain "foo", then the loop will run as
s[0] == t[0] == 'f'
s[1] == t[1] == 'o'
s[2] == t[2] == 'o'
s[3] == t[3] == 0
s[4] == t[4] // danger, past the end of the string
So, within the body of the loop, the code also checks to see if a[i] is 0 - if so, that means we've matched everything up to the 0 terminator, and the strings are identical.
So, basically, it goes...
s[0] == t[0] == 'f', s[0] != 0, keep going
s[1] == t[1] == 'o', s[1] != 0, keep going
s[2] == t[2] == 'o', s[2] != 0, keep going
s[3] == t[3] == 0, s[3] == 0, at end of s, strings match
for ( ; *s == *t; s++, t++)
does exactly the same thing as the first loop, but instead of using the [] operator to index into s and t, it just uses the pointers. Since there's nothing to initialize, the first expression is just left empty.
In the first case, the code after the for statement is checking to see if the end-of-string marker has been found, and if so the function returns 0.
In the case of the second for statement, the initialization part of the for statement is not filled in, so the statement starts with for( ;. This is perfectly legitimate.
Best of luck.
For loop has 3 parts - initialization , condition and loop expresion. All these are optional.
So this loop-
for (i = 0; s[i] == t[i]; i++)
It runs till character s[i] is equal to t[i]. So this is condition. If it is false loop breaks.
It is not necessary that condition is always based on length.
And this one -
for ( ; *s == *t; s++, t++)
As we see above intialization is optional and is not present here which is perfectly fine. Condition in this loop is also same i.e loop till characters are equal.
for (i = 0; s[i] == t[i]; i++) // It has no length
Actually this code is slightly dangerous, as it assumes that the passed strings are NULL-terminated (but read later). The cycle goes on only while the left-part of the strings are equal so, inside the loop, the only possible result to be returned is 0 (equal), when a NULL is encountered (the for(;;) condition ensures that the two strings both have the NULL in the same position).
About the length, to calculate it you should scan the whole string anyway... and two times (because there are two strings). This cycle instead combines all in one. Moreover, strings in C must be NULL terminated. Definitely, there is no other way to do this comparison!
for ( ; *s == *t; s++, t++) // what means this guys
This is about the same as the previous, but instead of dereferencing s and t using an index (and without touching them), they are modified to point to the characters, one after another. I believe this is faster, but depends on the compiler. Moreover, incrementing s and t makes you lose the start of the strings; but in this function it is not a problem.
About the syntax of for(;;), a comment already explained why it is written like this. The last part of the for(), between the semicolon and the closing bracket, is executed after every iteration. In this case we need to increment two variables, so there are two statements separated by a comma.
It doesn't have be a length. The for loop is run until the condition is true, so in this case it means it will be running until s[i] is not equal to t[i].
for ( ; *s == *t; s++, t++)
; here means that the first clause of the for loop is omitted. As
bot s and t are defined outside of for loop there is no need to define them here.
It's allowed by the C standard:
for ( clause-1 ; expression-2 ; expression-3 ) statement
(...)
Both clause-1 and expression-3 can be omitted. An omitted expression-2 is
replaced by a nonzero constant.
Some compilers such as clang produce a warning when an already defined variable is put in the first clause. For example this code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i = 0;
for (i; i < 10; i++)
puts("Hi");
return EXIT_SUCCESS;
}
compiled with clang produces a warning:
main.c:7:8: warning: expression result unused [-Wunused-value]
for (i; i < 10; i++)
^

K&R 1.6 Array. Not understanding the code [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I start reading the book K&R The C programmming ( 2nd edition). And I got stuck on the 1.6 Array; I just can't seem to figure out what the code does (even tho it says it counts digits, white spaces and others!). Here is the code:
#include <stdio.h>
/* count digits, white space, others */
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
ndigit[i] = 0;
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
printf("digits =");
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[i]);
printf(", white space = %d, other = %d\n",nwhite, nother);
}
So first it defines Integers, ( c,i,nwhite,nother);
After that it creates an array of 10 digits, ( 0 -9 )
After that it sets nwhite and nother to 0.
the for loops set I to 0, i < 10 means if its lower, add i = i + 1.
ndigit[i] = 0? I dont quite understand it, isnt i already is 0?
while ((c = getchar() != EOF) means What ever the input is and isnt at the end of the file?.
After that part I kinda got lost and I'm not sure what
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
Does at all.
And I don't quite understand why the for (i = 0; i < 10 ; +=i ) is repeated . I do understand English but some expensive use of words will confuse me. So if you dont mind, please keep it basic for me. I really hope there is someone out there who can help me understanding this code 100%. Because after all, who wants a programmer who cant even understand the code? :)
Let us step through the code and see what is happening.
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
In the first first line of code we are declaring[0] (to the compiler) that c, i, nwhite and nother will be integer variables. At this point, while we have declared these variables, we have not given them any value.
The next line we are declaring that ndigit will be an array of 10 integers, again no initialization is happening so we have no idea of what the value of those ten integers might be.
In the third line we are defining nwhite and nother to be zero, in other words we are initializing them to some value.
for (i = 0; i < 10; ++i)
ndigit[i] = 0;
In this loop, we are initializing the variable i to be zero, and we will increment it by one ever time through the loop, till the value become ten or larger. The body of the loop sets each element of the array to zero. This is a common c-idiom for initializing the elements of an array.
while ((c = getchar()) != EOF)
{
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
}
The next block of code does the actual counting. While the code in K&R is syntactically correct, I prefer enclosing the bode of the while loop with curly-braces, I find it easier to read, but it is a personal thing [1].
The condition of the while loop ((c = getchar()) != EOF), can be kind of confusing. We perform the operation in parenthesis first, which is c = getchar() which has the effect of getting the next character and assigning it to the variable c. (remember that in C a character (i.e. variable of type char), is just a small integer so we can assign a character type to an integer type). The assignment statement has a return value[2], in that it returns the value on the right side of the assignment operator, so the operation in parenthesis returns the value of getchar(), which is then compared to EOF, and if it doesn't equal EOF we enter the body of the while statement.
The first if statement checks to see if the character is a number. In ASCII, number have the value of 0x30 ('0') through 0x39 ('9'), so we check to see if the character is in that range. If it is, we increment the appropriate value in the ndigit array. For example, suppose that we have read in the character '5' which has an ASCII value of 0x35. Because 0x35 is between 0x30 and 0x39 we have a digit. Performing the subtraction c - '0' is equivalent to 0x35 - 0x30 which equals 0x05. We then use this as the index into the array, and increment the appropriate value with ++ndigit[c-'0'].
The next branch of the if-block, check to see if c is a a white space, i.e. the
expression c == ' ' || c == '\n' || c == '\t' check to see if c is a space or if c is a new-line or if c is a tab. If c is one of those characters we then
increment nwhite.
Finally, the else branch is taken if we do not have a digit or white space, and we then increment nother.
printf("digits =");
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[i]);
printf(", white space = %d, other = %d\n", nwhite, nother);
}
The last bit of code just prints out the results. Because we want to look at all ten elements of the ndigit array, we need to step through the array again so we use the for loop structure to look at each element of the array.
Hopefully, this clears up some stuff. Something you may want to try is to modify this code so that it counts the of letters that are appearing in the input as well. First just try and count letters, with out regard to case, and then see if you can count upper and lower case letters.
notes:
[0] Declaring a variable is just specifying the name and type of the variable, so int x; is just a declaration. We are providing just enough information to the compiler that it can check our usage of x. A definition is when we assign a value to the variable, so x=5; is a definition. Note that the declaration and definition can be combined into a single line int x = 5;. At the assembly level, a declaration causes storage to be allocated for the variable, but does not set what the storage location contains.
[1] The C grammar says that the curly-braces are not needed for a while block if
it consists of a single statement, i.e.
while(n > 10)
c--;
and
while(n > 10)
{
c--;
}
are equivalent, I just find the second easier to read. Also, the C grammar
says that curly braces are not need for the body of an if statement if the body consists of a single statement, so for example
if(n < 10)
n = n - 10;
and
if(n < 10)
{
n = n - 10;
}
are equivalent.
Finally, the else if and end all are part of the if statement so the statement
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
is effectively a single statement, and thus why the curly braces are not needed.
Also, for readability and maintainability I tend to use curly braces with if / else if / else blocks - but again it is a personal think.
[2] The assignment statement has a return value of the left hand side, so a simple expression of a = 10; the return value is just ignored. Having a return value allows us to write something like, a = b = c = 10 which will have the effect of setting a, b and c to 10. In addition of having a return value, the assignment operator is right associative, so the above expression would be
interpreted as a = (b = (c = 10)).
-T.

Wrong answer while Changing the upper case letters to lower case and vice versa

I can't identify the mistake. In place of a, A has to be printed but some other letter is printing. Same in the case of other letters. Please help to find the mistake.
#include<stdio.h>
#include<conio.h>
#include<string.h>
int main()
{
char m[20];
int i;
printf("Enter any string:");
gets(m);
for(i=0;i<=strlen(m);i++)
{
if(m[i]>=97&&m[i]<=122)
m[i]=m[i]-26;
else
m[i]=m[i]+26;
}
printf("%s\n",m);
return 0;
}
Change the loop the following way
for(i=0; i < strlen(m); i++ )
^^^
Otherwise you overwrite the terminating zero.
And instead of magic numbers 97 and 122 it is better to use letters 'A' and 'Z'.
For example
if ( m[i] >= 'A' && m[i] <= 'Z' )
Also it seems this statement
m[i]=m[i]-26;
is wrong
I think you mean the following
if ( m[i] >= 'A' && m[i] <= 'Z' )
m[i] = m[i] + 'a' - 'A' ;
else if ( m[i] >= 'a' && m[i] <= 'z' )
m[i] = m[i] - 'a' + 'A' ;
Take into account that there are standard functions isupper and islower and correspondingly toupper and tolower declared in header <ctype.h>
Also function gets is not supported any more by the C Standard because it is unsafe. I advice to use fgets instead.
The value will be 32 not 26.
if(m[i]>=97&&m[i]<=122)
m[i]=m[i]-32;
else
m[i]=m[i]+32;
Better to use for checking isupper and islower. Then change by tolower and toupper. Then you don't have to think about ASCII value.
if(isupper(m[i]))
{
m[i]=tolower(m[i]);
}
else
{
m[i]=toupper(m[i]);
}
Just change 26 to 32, since between the uppercase letters and lowercase characters, you have some other ascii values like [ \ ] ^ _ ...
Here's an ascii table for you to check for yourself
EDIT: Also, when you fix that, you might want to change your termination condition (you'll probably get an OutOfBounds Exception if you don't) to i<strlen(m), as you're working with a zero-based system (i,e starts with 0 and ends with strlen(m)-1, vs starting with 1 and ending with strlen(m)).
Your conversion of an uppercase letter to a lower case letter is wrong.The ascii difference is 32 and not 26.
Also you should run your loop till strlen(m)-1 as the characters are stored from zero index.
for(i=0;i<strlen(m);i++)
{
if(m[i]>=97&&m[i]<=122)
m[i]=m[i]-32;//changing lower case to upper requires subtraction of 32
else
m[i]=m[i]+32;
}

The use of tolower and storing in an array

I am trying to trace through this problem and can not figure out how the star is goes through the while loop and is stored in the array. Is * stored as 8 because of tolower? If anyone could please walk through the first for - to second for loop please I would be eternally grateful.
#include <stdio.h>
#include <ctype.h>
int main()
{
int index, freq[26], c, stars, maxfreq;
for(index=0; index<26; index++)
freq[index] = 0;
while ( (c = getchar()) != '7')
{
if (isalpha(c))
freq[tolower(c)-'a']++;
printf("%d", &freq[7]);
}
maxfreq = freq [25];
for (index = 24; index >= 0; index--)
{
if (freq[index] > maxfreq)
maxfreq = freq[index];
}
printf ("a b c d e f\n");
for (index = 0; index < 5; index++)
{
for (stars = 0; stars < (maxfreq - freq[index]); stars ++)
printf(" ");
for (stars = 0; stars < (freq[index]); stars++)
printf("*");
printf("%c \n", ('A' + index) );
printf(" \n");
}
return 0;
}
It seems that this code is a histogram of sorts that prints how many times a given character has been entered into the console before it reaches the character '7'.
The following code:
for(index=0; index<26; index++)
freq[index] = 0;
Is simply setting all of the values of the array to 0. This is because of the fact that in C, variables that are declared in block scope (that is, inside a function) and that are not static do not have a specific default value and as such simply contain the garbage that was in that memory before the variable was declared. This would obviously affect the results that are displayed each time it is run, or when it is run elsewhere, which is not what you want I'm sure.
while ( (c = getchar()) != '7')
{
if (isalpha(c))
freq[tolower(c)-'a']++;
printf("%d", &freq[7]);
}
This next section uses a while loop to continue accepting input using getchar() (which gets the next character of input from STDIN in this case) until the character "7" is reached. This is due to the fact that assigning a value (such as "c = getchar()") allows the value to be used in such a way that it can be compared using "! = '7'". This allows us to continue looping until the character that is accepted from STDIN is equal to '7', after which the while loop will end.
Inside the loop itself, it's checking the value that has been entered using "isalpha()", which returns true if the character is an alphabetic letter. By using "tolower()" and returning that value to be subtracted by the character value of 'a', we are basically finding which character in the alphabet this is numerically. An example would be if we took the letter 'F'. Capital 'F' is stored as the value 70 in the background. tolower() checks to see if it is an uppercase character, and if it is, it returns the lowercase version of it (in this case, 'f' == 102). This value is then subtracted by 'a' (stored as 97) which returns the value 6 (which, when counting from 0, is the position of 'F' in the alphabet). This is then used to target that element of the array and to increment it, which tells us that another "F" or "f" has been entered.
maxfreq = freq [25];
for (index = 24; index >= 0; index--)
{
if (freq[index] > maxfreq)
maxfreq = freq[index];
}
This next section sets the variable "maxfreq" to the last value (how many times 'Z' was found), and iterates downwards, changing the value of maxfreq to the highest value that is found (that is, the largest number of any given character that is found in the array). This is later used to format the output to make sure that the letters line up correctly and the number of stars and spaces are correct.

Resources