C Program not Comparing chars correctly - c

I am working on this C code and I am confused why this is not working. I have looked at other questions here for comparing 2 chars and I have done it the exact same way but for some reason it isn't working.
What happens when it runs is that it will work for t and o, but not for c, even though I have implemented them all the same way.
Split_string was provided to us (no bugs) and returns the number of words in the string inputted via the keyboard. It also takes in an array of strings and puts each word at a different index.
Any suggestions would be greatly appreciated
char input[100];
printf("What commmand would you like to use? t, o, or c\n");
while(fgets(input, 100, stdin)!=NULL){
char ** ptr = malloc(sizeof(char*)*10);
int wordno = split_string(input, ptr);
if((*ptr[0]=='t') && wordno==1) {
text(root_ptr);
} else if(*ptr[0]=='t' && wordno>1){
printf("No arguments for function t\n");
} else if(*ptr[0]='o' && wordno==9){
open(root_ptr);
} else if(*ptr[0]=='o' && wordno != 9){
printf("Need 8 attributes to open o\n");
} else if(*ptr[0]=='c' && wordno==2){
open(root_ptr);
} else if(*ptr[0]=='c' && wordno !=2){
printf("Only need 2 arguments to copy\n");
} else {
printf("Please enter a value command\n");
}
printf("Enter t to text, o to open or c to copy\n");
}

Check the following line. There is a = missing, so you actually assign o to the first element of your array instead of comparing with o. Afterward, it can never be c.
} else if(*ptr[0]='o' && wordno==9){

The error is here:
else if(*ptr[0]='o' && wordno==9){
where you force the first character to be 'o'. For that reason I usually write comparisons in the Yoda form:
if (('o' == (*ptr[0])) ...
even if it at first it looked awkward and is overkill. If an equal sign you forget, an error the compiler will throw.
However, this kind of behaviour should have been caught by activating the full warnings on the compiler. I strongly suggest you to keep them on at all times.
Also, you allocate the memory again at each cycle, causing a leak (this won't bite you very soon, if at all, but still):
char ** ptr = malloc(sizeof(char*)*10);
Finally, you might be better served by a switch statement:
switch(*ptr[0]) {
case 't':
...
break;
...
default:
printf("Huh?\n");
break;
}

Related

C - Two types of formatted user input with an unknown number of inputs

I want the user to be able to input two types of input like: "C[some size_t]" and "O[some memory address]" and depending on whether it's a C or O at the beginning, I'll call different functions. I also want to be able to take in an unknown number of those inputs and in any order.
My way of going around it was something like this:
int main()
{
// variables
while (1) { // Infinite loop to take in multiple unknown amount of inputs?
while (fgets(input, BUFFER_SIZE, stdin)) {
if (sscanf(input, "%c%zu", &branch, &num) == 2) {
if (strcmp(&branch, "C")
// function call
} else if (sscanf(input, "%c%c", &branch, (char *)addr) == 2) {
if (strcmp(&branch, "O")
// function call
}
}
}
return 0;
}
I understand why it's not working of course and I know my not-solution is wrong but I have no idea how else to go about this. The code takes in the first input and just hangs and if I start with an input beginning with O, it'll go into the first if statement when it's not supposed to. I'm also not sure if my while(1) loop is the correct way to deal with multiple user inputs.
You try to read the branch char and the respective argument in one single go – however the argument differs in both cases. So you need first to read the character, then decide and only then scan the argument – as soon as you know what to scan at all and thus are able to select the appropriate format string.
As you just read in any character you could do so a bit simpler with getc, by the way:
char branch = getc(); // instead of `if(scanf("%c", &branch) == 1)`
// note: would have been one single scan (branch) only!
if(branch == 'C')
{
// scan num
}
else if(branch == 'O')
{
// scan addr
}
else
{
// error handling
}
or alternatively (I personally would prefer)
char branch = getc();
switch(branch)
{
case 'C':
// scan num
break;
case 'O':
// scan addr
break;
default:
// error handling
break;
}
Note that strcmp requires null-terminated strings (char arrays) and cannot be used for comparing single characters – these need to be compared via equality operator, see above.

Switching letters (no strings or strings functions)

I want to switch the word "cat" into "dog" each time it appears in the text.
I can't use string or strings functions.
my code:
#include <stdio.h>
int main()
{
int i; // loop counter
int size; // size of arry
int input[20];
printf("enter text here\n");
while((input[i] = getchar()) != '\n') // input text to the arry
{
if(input[i]=='c' && input[i+1]=='a' && input[i+2]=='t') // switching characters
{
input[i]='d'; input[i+1]='o'; input[i+2]='g';
}
i++;
size++;
}
i=0; // reset for next loop
while(i <= size) // printing the text out ofthe arry
{
putchar(input[i]);
i++;
}
printf("\n");
return 0;
}
output:
enter text here
cat
cat
ȵm�� $$ŵ��p��$���Zտ ��$��M��v��������������������� ������������!��d#8 $
�
�����������5_Segmentation fault
Few problems here.
Uninitialized local variables.
int i = 0; // loop counter
int size = 0; // size of array
You are checking a and t chars which are not read yet.
Hence check for the t in current inputted char if it is matching then check for a and c
in previous entered chars as below.
if(i>=2 && input[i-2]=='c' && input[i-1]=='a' && input[i]=='t') // switching characters
{
input[i]='g'; input[i-1]='o'; input[i-2]='d';
}
This problem is perfect match for a finite-state machine.
Here's a flowchart of how a finite-state machine could do the job:
It might be a surprise that the non-matching cases go back to checking if the latest character matches 'C', rather than just printing it and getting a new one. The reason for this is that if we read say ccat or cacat, we want to check if we still match a (shorter) prefix, in this case c.
As a different example, consider if we were trying to match cocoa, and our input was cococoa. At the fifth character, we read c instead of a (already having matched coco, but not output anything yet), so we'd need to output co, and go back to matching for the second c.
We humans do not normally build such state machines by hand. We already have one for strings, either as a library or built-in to POSIX-compatible C libraries (Linux, Mac, BSDs): regular expression matching. If we use the basic POSIX ones, then regcomp() builds an efficient state machine based on our specifications, and regexec() processes input data on it.
This particular case is simple enough to implement by hand, though. What we'll want to do, is to put the first state ("Get next char") outside a loop, do a loop that continues as long as "char = EOF" is not true, and do the rest inside the loop. The final "Done" state is then after the loop. In pseudocode:
ch = Next char
While ch != EOF:
If ch != 'c':
Output ch
ch = Next char
Continue
End If
# The second "Get next char" in the flowchart:
ch = Next char
If ch == EOF:
Output 'c'
Break
Else
If ch != 'a':
Output 'c'
Continue
End If
# The third "Get next char" in the flowchart
ch = Next char
If ch == EOF:
Output 'c'
Output 'a'
Break
Else
If ch != 't':
Output 'c'
Output 'a'
Continue
End If
# 'c' 'a' 't' matched (with ch == 't').
Output 'd'
Output 'o'
Output 'g'
ch = Next char
End While
Done
A C program that reads standard input, converts each occurrence of cat to dog, case sensitive, can therefore be written as
#include <stdlib.h>
#include <stdio.h>
void cat_to_dog(FILE *in, FILE *out)
{
int ch;
ch = fgetc(in);
while (ch != EOF) {
if (ch != 'c') {
fputc(ch, out);
ch = fgetc(in);
continue;
}
ch = fgetc(in);
if (ch == EOF) {
fputc('c', out);
break;
} else
if (ch != 'a') {
fputc('c', out);
continue;
}
ch = fgetc(in);
if (ch == EOF) {
fputc('c', out);
fputc('a', out);
break;
} else
if (ch != 't') {
fputc('c', out);
fputc('a', out);
continue;
}
fputc('d', out);
fputc('o', out);
fputc('g', out);
ch = fgetc(in);
}
}
int main(void)
{
cat_to_dog(stdin, stdout);
return EXIT_SUCCESS;
}
The issue with finite state machines is that the code tends to be write-only. To understand the code, or to verify or maintain it in any time scales, you really need the definition of the finite-state machine, so one can compare the implemented code to the finite-state machine.
And here we finally get to the point of this "answer": Proper Documentation.
Solving a problem once using carefully-crafted, extremely tight and efficient code, is worth nothing if there is no way to modify or fix bugs in the code. (Even the very best programmer in the world makes mistakes and bugs at various levels of complexity. If someone claims they do not, they're lying.)
We could document the finite state machine by explaining it in comments interspersed with the above code. That would be fine; comments should always explain the intent of the programmer, the purpose or the task a piece of code is intended to accomplish. We often instead write comments that tells what the code does, which is less than useful, because we can easily read the code to see what it does. What we do not know, is whether the code matches the programmers intent, or whether the programmers intent is a valid solution to the underlying problem!
Another possibility would be to include the diagram, perhaps numbering the actions (ovals) and tests (parallelograms), and add comments in the code referring to the diagram. This is easier, but not as easy to follow (because you need to constantly cross-reference the code and the diagram).
It is, sadly, very common to omit the documentation part ("I'll do it later when I have more time"), and simply verify that the code works for correct input. It is often impossible to fully test the code for all possible inputs (although this one is so simple it can be), so a lot of bugs are left uncovered. Without documentation, so that a human can check the code and try and assess if it is logically correct (i.e., that the "flowchart", or finite state machine that it implements, is correct), and whether the code matches the working model or not, bugs are only found by being bitten by them in practice. Which is nasty.
Finite-state machines are a prime example of how important comments (and documentation) are, but it really applies to all code you write. Learn to try to describe your reasoning (model of the solution) and intent (what you want the code to accomplish) in your comments, and write a lot of comments, from the get go. It is very hard to get into the habit later on; I'm personally still struggling with this, after decades of programming. If a comment is later found to be unnecessary, it takes less than a fraction of a second to remove it; but if it explains a crucial quirk or complex detail that us humans don't normally notice, it may save hours, days, or even weeks of developer time later on.
This also means that the practice of commenting out unused code is not very useful, because the actual comments very quickly diverge from the code the compiler (or interpreter) sees. Instead, learn to use a version control system for your sources; I recommend git. It is available for just about all operating systems (see here), and you can use it both locally on your computer, as well as for distributed projects, in case you want to put your code on GitHub or similar services (or even set up your own git server). That way you can keep your code and its comments in sync; and when modifying your code, you can separately describe the reasons for those changes (changesets). After you get the hang of it, you'll find it is not a burden, but actually speeds up your code development!
Kiran mentions in his answer that "You are checking a and t chars which are not read yet". You can get around this by exploiting the use of argc and argv.
This is my version of your program using argc and argv. You'll notice that it also prevents you from limiting your input buffer (i.e. no input[20]).
#include <stdio.h>
int main(int argc, char **argv)
{
int i = 0, j = 0;
for(i=1; i<argc; i++)
{
while(argv[i][j] != '\0')
{
if(argv[i][j] == 'c')
{
if(((argv[i][j+1]) == 'a') && (argv[i][j+2] == 't'))
{
argv[i][j] = 'd';
argv[i][j+1] = 'o';
argv[i][j+2] = 'g';
}
}
printf("%c", argv[i][j]);
j++;
}
j=0;
printf(" ");
}
printf("\n");
return 0;
}
Sample input and output:
$ ./test my favourite cartoon when i was a kid was catdog
my favourite cartoon when i was a kid was dogdog
$ ./test i used to love cats but now i love dogs
i used to love dogs but now i love dogs
PS: Just in case you were born a little too late or didn't watch many cartoons on TV; here's the reference: https://en.wikipedia.org/wiki/CatDog.
You're trying to access input[i], input[i + 1] and input[i + 2].
Use :
while (input[i + 2] && input[i + 2] != '\n')
In your case :
#include <stdio.h>
int main()
{
int i = 0; // loop counter
int size = 0; // size of array
int input[20];
printf("enter text here\n");
while((input[i] = getchar()) != '\n' && i < 19) // input text to the array
{
/* if(input[i]=='c' && input[i+1]=='a' && input[i+2]=='t') // switching characters
{
input[i]='d'; input[i+1]='o'; input[i+2]='g';
}
*/
i++;
size++;
}
input[i] = 0;//ALWAYS null-terminate arrays.
if (i >= 2);
while (input[i + 2]) {
if (input[i] == 'c' && input[i + 1] == 'a' && input[i + 2] == 't') {
input[i] = 'd';
input[i + 1] = 'o';
input[i + 2] = 'g';
}
}
}
i=0; // reset for next loop
while(i < size) // printing the text out ofthe arry
{
putchar(input[i]);
i++;
}
printf("\n");
return 0;
}

Compare character by character 2 strings

I am trying to code a program that tells me if 2 strings are identcal. If they have one different chracter they are not.
I have this code, but it does not work, why?
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {
char str1[30], str2[30];
int i;
printf("\nEnter two strings :");
gets(str1);
gets(str2);
for (i=0;str1[i]==str2[i];i++)
if (str1[i]!=str2[i]){
printf("They are not identical");
}
else continue;
return (0);
}
It compiles with 0 errors and 0 warnings, but when I introduce 2 not identical strings it returns nothing. (The same happens when I introduce 2 identical strings, but that is how is supposed to be)
What should I do to fix it?
There is one important thing wrong here. First of all: The classic "c style string" is null terminated. Allthough there are other alternatives (like storing the length outside of the string), the null terminated string is part of the language (as string literals in code are null terminated by the compiler), and the runtime library (most string functions handle the \0 at the end of the string).
gets also appends a \0 at the end of the entered string:
http://www.cplusplus.com/reference/cstdio/gets/
You are comparing not only the entered strings, but also anything (random) after that string in memory.
It should look like this:
for(int i=0;str1[i]==str2[i];i++){
if(str1[i]==0) {
printf("equal");
}
}
printf("not equal");
There are other alternative, like using pointer. But on modern compilers they should produce roughly the same machine code.
Please note that there are C runtime library functions to compare strings:
strcmp is the most basic one, just two char *:
strncmp allows to specify the maximium chars to compare, do compare a part of a string:
There are other, just check out the links.
Please note that it's better to use the library functions, because even if in such a "simple" function. There are optimized ways to compare string. Like comparing in native word sizes. On 32 bit platforms you spend four time more time in comparation, not including the masking needed to perform byte wise operations.
Your for loop is:
for (i=0;str1[i]==str2[i];i++)
if (str1[i]!=str2[i]){
printf("They are not identical");
}
else continue;
Let's say str1 is "abc" and str2 is "xyz".
The conditional in the for loop will evaluate to false for i = 0. Hence, you will never get to the statement:
if (str1[i]!=str2[i]){
Consequently, you will never execute:
printf("They are not identical");
You can fix the logic error by using:
for (i=0; str1[i] != '\0' && str2[i] != '\0'; i++)
{
if (str1[i]!=str2[i]) {
break;
}
}
// If at end of the loop, we have reached the ends
// of both strings, then they are identical. If we
// haven't reached the end of at least one string,
// then they are not identical.
if ( str1[i] != '\0' || str2[i] != '\0' )
{
printf("They are not identical");
}
I have this code, but it does not work, why?
Because your looping condition str1[i]==str2[i] will make the inner if condition be always false.
What should I do to fix it?
Simple code:
for ( i=0; str1[i]==str2[i] && str1[i]!='\0'; i++) {
}
if ( str1[i]!=str2[i] ) {
printf("They are not identical");
}
or
i=0;
while ( str1[i]==str2[i] && str1[i]!='\0' ) {
i++;
}
if ( str1[i]!=str2[i] ) {
printf("They are not identical");
}
Let's say you have two string in which the first character is different. then you will not enter the loop as the condition of the loop (str1[i]==str2[i]) fails, therefore the condition should be ( str1[i]!='\0' && str2[i]!='\0' ). The '\0' is the last character of the c-style string.
You can also use string built in functions like " strcmp(str1,str2) ".

Why am I getting a debug assertion failed error on running the code

When I enter a password in my program below and press enter I get a debug
assertion error, specifically isctype.c line 56
Expression:(unsigned)(c+1) <= 256
Could someone help me get around this please?
Code:
int main()
{
int j=0;
char pass[100];
int upper=0, lower=0, digit=0, sc=0;
printf("Enter your password:\n");
scanf("%s",&pass);
while(j!=' '){
if(isalpha(pass[j])){
if(isupper(pass[j])){
upper++;
}
else{
lower++;
}
}
else if(isdigit(pass[j])){
digit++;
}
else{
sc++;
}
j++;
}
if(upper==0||lower==0||digit==0||sc==0){
printf("Password must contain atleast one upper case, one lower case, one digit and a special character");
}
else{
printf("Good to go");
}
return 0;
_getch();
}
Replace
while (j!=' ')
by
while (pass[j] != 0)
You want to loop as long as pass[j] is different from zero. Remember, strings are terminated by a zero.
It looks like the problem in your code is
while(j!=' ')
which is checking j against space (' ') which is having ASCII value of 32 (decimal).
Essentially, you're unconditionally using pass array elements having index 0 to 31.
Then, pass is an automatic local variable and you did not initialize it. It contains indeterminate value.
If, your input is less than 31 characters, the remaining element of pass will remain uninitialized, and using them further (as the argument to is....() family, here) may lead to undefined behaviour.
Solution: You don't need to check for a space, (as %s does not accept one). Instead you should check for the null terminator \0. Change your code to
scanf("%s",&pass); to scanf("%99s",pass); to avoid possible buffer overflow.
while(j!=' ') to while(pass[j]) to loop until the string terminator null.
That said,
using _getch() after unconditional return statement does not make any sense. You can straight-away remove that _getch().
The recommended signature of main() is int main(void).

C segmentation fault errors with feof() and fgetc()

Can anyone help me solve my dilemma? When I compile my program I get no errors or warnings. When I go to actually run the executable, though, I get a segmentation error. If I'm to understand correctly, this happens because a pointer is in short being used incorrectly. I get a specific error on the feof(srcIn) line and I'm not sure why. The FILE* srcIn is never assigned a new value aside from the srcIn = fopen(argv[0], "r") value at the beginning of the program. I had originally had this solution implemented in C++ and needed to changed it to C for reasons. Anyways, in the C++ one I did essentially the same exact thing except using srcIn.eof() as the the condition and srcIn.get(something) as the reading method. and it compiled and ran without any problems.
int chara;
int line[maxLineLength+1];
void nextch(void){
const int charPerTab = 8;
if(charCounter == charLineCounter){
if(feof(srcIn)){
printf("\n");
isEOF = TRUE;
return;
}
printf("\n"); lineCounter++;
if(chara != '\0'){ printf("%c", line[charLineCounter-1]); } // first character each line after the first line will be skipped otherwise
charLineCounter = 0; charCounter = 0;
while(chara != '\n'){
chara = fgetc(srcIn);
if(chara >= ' '){
printf("%c", chara);
line[charLineCounter] = chara; charLineCounter++;
}
else if(chara == '\t'){ // add blanks to next tab
do{ printf(" "); line[charLineCounter] = ' '; charLineCounter++; }
while(charLineCounter % charPerTab != 1);
}
}
printf("\n"); line[charLineCounter] = chara; charLineCounter++; line[charLineCounter] = fgetc(srcIn); charLineCounter++;
// have to get the next character otherwise it will be skipped
}
chara = line[charCounter]; charCounter++;
}
EDIT:
I forgot to mention that I'm not even actually going into main when I get the seg fault. This leads me to believe that the executable itself has some sort of problem. gdb tells me the seg fault is happening at line:
if(feof(srcIn))
Any ideas?
I've got a haunting suspicion that your two-or-four-character indents aren't sufficient to let you see the real scope of the program; it could be as easy as #mu is too short and #Null Set point out, that you've got an argv[0] when you meant argv[1], and it could be as #Lou Franco points out and you're writing past the end of your array, but this code sure smells funny. Here's your code, run through Lindent to get larger tabs and one-statement-per-line:
int chara;
int line[maxLineLength + 1];
void nextch(void)
{
const int charPerTab = 8;
if (charCounter == charLineCounter) {
if (feof(srcIn)) {
printf("\n");
isEOF = TRUE;
return;
}
printf("\n");
lineCounter++;
if (chara != '\0') {
printf("%c", line[charLineCounter - 1]);
} // first character each line after the first line will be skipped otherwise
charLineCounter = 0;
charCounter = 0;
while (chara != '\n') {
chara = fgetc(srcIn);
if (chara >= ' ') {
printf("%c", chara);
line[charLineCounter] = chara;
charLineCounter++;
} else if (chara == '\t') { // add blanks to next tab
do {
printf(" ");
line[charLineCounter] = ' ';
charLineCounter++;
}
while (charLineCounter % charPerTab != 1);
}
}
printf("\n");
line[charLineCounter] = chara;
charLineCounter++;
line[charLineCounter] = fgetc(srcIn);
charLineCounter++;
// have to get the next character otherwise it will be skipped
}
chara = line[charCounter];
charCounter++;
}
You're checking whether or not you've read to the end of the file at the top, in an if statement, but you never check for eof again. Never. When you read from input in your while() loop, you use '\n' as your exit condition, print the output if the character is above ' ', do some tab expansion if you read a '\t', and you forgot to handle the EOF return from fgetc(3). If your input file doesn't have an '\n', then this program will probably write -1 into your line array until you segfault. If your input file does not end directly on a '\n', this program will probably write -1 into your line array until you segfault.
Most loops that read one character from an input stream and operate on it are written like this:
int c;
FILE *f = fopen("foo", "r");
if (!f) {
/* error message if appropriate */
return;
}
while ((c=fgetc(f)) != EOF) {
if (' ' < c) {
putchar(c);
line[counter++] = c;
} else if ('\t' == c) {
/* complex tab code */
} else if ('\n' == c) {
putchar('\n');
line[counter++] = c;
}
}
Check the input for EOF. Read input from only one spot, if you can. Use one table or if/else if/else if/else tree to decide what to do with your input character. It might not come natural to use the array[index++] = value; idiom at first, but it is common in C.
Feel free to steal my suggested loop format for your own code, and pop in the complex tab expansion code. It looked like you got that right, but I'm not positive on that, and I didn't want it to distract from the overall style of the loop. I think you'll find extending my code to solve your problem is easier than making yours work. (I fully expect you can, but I don't think it'd be fun to maintain.)
argv[0] is the name of your program so your fopen(argv[0], 'r') is probably failing. I'd guess that you want to open argv[1] instead. And, of course, check that the fopen succeeds before trying to use its return value.
It should probably be srcIn = fopen(argv[1], "r") instead. The 0th string parameter your main gets is normally the name of the program, and the 1st parameter is the first command line paramter you passed to the program.
It might not be in this function, but if the problem is here, I'd be most suspect of going out of bounds on line. Are you ever writing more than maxLineLength characters? You should put a check before you ever index into line.
Edit: You seem to be confused about what this error even means -- I will try to clear it up.
When you get a segmentation fault, the line that it happens on is just the line of code where it was finally detected that you have corrupted memory. It doesn't necessarily have anything to do with the real problem. What you need to do is to figure out where the corruption happened in the first place.
Very common causes:
calling free or delete on a pointer more than once
calling the wrong delete on a pointer (delete or delete[])
using an uninitialized pointer
using a pointer after free or delete was called on it
going out of bounds of an array (this is what I think you did)
casting a pointer to a wrong type
doing a reinterpret_cast where the target type cannot be reinterpreted correctly
calling functions with improper calling conventions
keeping a pointer to a temporary object
And there are many other ways.
The key to figuring this out is to
assume that your code is wrong
look for these kinds of problems by inspection in the code path (if short)
use tools that can tell you that you have these problems at the line of code where you did it
realizing that the line of code where the segmentation fault happens is not necessarily the bug.

Resources