Not sure why optimizer is optimizing my method incorrectly - c

I'm new to C (so there's every good chance I'm doing something fundamentally wrong or bad), and working on a kattis problem, https://open.kattis.com/problems/abc.
I'm running in to fun with what appears to be the GCC optimiser and I'm trying to understand why or what I'm doing wrong. Here's the simplest replication case I can come up with:
#include <stdio.h>
#include <string.h>
int lookup(char input){
// This will return 2 on invalid input. Not ideal, but we don't have to worry about invalid inputs like that
fprintf(stderr, "Asked to compare: %s\n", &input);
if (strcmp("A", &input) == 0){
//fprintf(stderr, "It's an A\n");
return 0;
} else if (strcmp("B", &input) == 0){
//fprintf(stderr, "It's a B\n");
return 1;
} else {
return 2;
};
}
int main(void){
char input[3];
if (scanf("%3s", input) != 1){
fprintf(stderr, "Something went wrong reading input\n");
return -1;
};
printf("Desired Order: %s\n", input);
printf("%d %d %d\n", lookup(input[0]),
lookup(input[1]),
lookup(input[2])
);
}
An example input file for triggering this bug has a single line:
CAB
If I compile with without optimisations:
$ cc -std=gnu11 -static -lm simple.c -o simple && cat input | ./simple
Desired Order: CAB
Asked to compare: B
Asked to compare: A
Asked to compare: C
2 0 1
With optimisations enabled, note it's falling through to the else section:
$ cc -O2 -std=gnu11 -static -lm simple.c -o simple && cat input | ./simple
Desired Order: CAB
Asked to compare: B
Asked to compare: A
Asked to compare: C
2 2 2
Things I've noticed so far:
If I uncomment the fprintf after the strcmp("A", &input), the code works fine even with optimisations enabled (that's what got me wondering about optimisations breaking my code in the first place).
If I uncomment the fprintf after the strcmp("B", &input) the code fails when optimised.
If I comment out the "Desired Order:" printf, the code works fine even with optimisations.

char input[3];
but you wrote three characters to it. Need 1 more for null terminator.
char input[4];
And here we have
fprintf(stderr, "Asked to compare: %s\n", &input);
No. That's a character not a string so we want
fprintf(stderr, "Asked to compare: %c\n", input);
and we also have
strcmp("A", &input) == 0
but input is a char so we want
'A' == input
and the same for 'B'

Related

scanf keeps running nonstop

I have been trying to run the scanf() on my mac, but it never worked (took forever to run the program). Everything else like the printf works fine!
#include <stdio.h>
#include <stdlib.h>
int main(){
char name[20];
printf("What is your name? \n");
scanf("%19s", name);
return 0;
}
terminal
[Running] cd "/Users/yiminghuang/Documents/C/" && gcc scanf4.c -o scanf4 && "/Users/yiminghuang/Documents/C/"scanf4
[Done] exited with code=null in 8.611 seconds
[Running] cd "/Users/yiminghuang/Documents/C/" && gcc scanf4.c -o scanf4 && "/Users/yiminghuang/Documents/C/"scanf4
[Done] exited with code=null in 10.384 seconds
[Running] cd "/Users/yiminghuang/Documents/C/" && gcc scanf3.c -o scanf3 && "/Users/yiminghuang/Documents/C/"scanf3
[Done] exited with code=null in 15.999 seconds
I am new to C programming, so please excuse me if I fail to answer your question correctly!
Now, the program you wrote works perfectly fine but as soon as you enter a string separated by a space, it only takes the characters before the space.
To solve this problem, you can use fgets() function of C.
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
int main(){
char name[MAX];
printf("What is your name? \n");
fgets(name, MAX, stdin);
printf("String = %s", name);
return 0;
}
//i have used fgets() here for getting the input
//it is a better option than gets()
//since it bounds your array and prevents buffer overflow
I have also added a printf() to check if the string is stored correctly.
IMPORTANT: fgets() also consider the newline character i.e. '\n' as a part of your string. So better to keep that in mind.
Check this question to know more about fgets()
Regards!

Can not reallocate memory in a very peculiar circumstance

Almost minimal reproducible example:
prog.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *buffer;
int c;
size_t bufsiz = 1024, i = 0;
if (!(buffer = malloc(bufsiz))) {
fputs("malloc() failed!\n", stderr);
return 1;
}
while (EOF != (c = fgetc(stdin))) {
buffer[i] = c;
if (++i == bufsiz && !(buffer = realloc(buffer, bufsiz *= 2))) {
fputs("realloc() failed! (loop)\n", stderr);
return 1;
}
}
buffer[i] = '\0';
if (!(buffer = realloc(buffer, i))) {
fputs("realloc() failed! ", stderr);
fprintf(stderr, "%d\n", i);
return 1;
}
fputs(buffer, stdout);
return 0;
}
I use this command to compile and run:
gcc prog.c -o prog
This command copies the content of prog.c to exp as expected:
cat prog.c | ./prog > exp
This command prints the error message “realloc() failed! 0”:
cat prog.c | ./prog > prog.c
I have yet to find out the reason behind this peculiar behavior...
P.S.: I am using GNU cat and bash
Congratulations, you've (re-)discovered a bug in your system's implementation of realloc, whereby "success" resizing to 0 is indistinguishable from an error. As specified, if realloc returns a null pointer, it has failed and the old object still exists. But some historical implementations treat realloc(p,0) as free(p). Future versions of the C standard allow for this behavior, and deprecate the use of realloc with a zero size, so if you want to use realloc like this you should make sure you are not passing a zero size.
As noted by Eric Postpischil in a comment:
Where does your program put a null character at the end of the string in the buffer?
the fact that 0 is a possible size for your buffer is indicative of a problem - you forgot to reserve space for terminating the string - and if you fix this, even a zero-length string takes a nonzero number of bytes.
In cat prog.c | ./prog > prog.c, the shell parses the command, sees there is a redirection into prog.c, and opens prog.c for writing, which erases any previous contents of the file. Then cat prog.c sees an empty file and copies it to standard output. ./prog faithfully reproduces this empty stream.

Operator == doesn't work in C

I'm getting a weird error while writing my program in C.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include "defs.h"
int main (int argc, char* argv[])
{
int boardSize = atoi(argv[2]);
int generations = atoi(argv[4]);
int gamesort = atoi(argv[1]);
printf("2 is %d 1 is %d 4 is %d name of file is %s \n",boardSize,gamesort,generations,argv[3]);
if (1==1)
{
printf("yes");
ZeroPlayersGame(boardSize, generations,argv[3]);
}
else//(gamesort==2)
{
TwoPlayersGame(boardSize, generations,argv[3]);
}
return 0;
}
And here is the error im getting from the Terminal:
ise#ubuntu:~/Desktop$ make
gcc -c main.c defs.c gameIO.c zeroPlayer.c twoPlayer.c
gcc gameIO.o defs.o zeroPlayer.o main.o twoPlayer.o -o prog
ise#ubuntu:~/Desktop$ ./prog 1 2 "l.txt" 3
2 is 2 1 is 1 4 is 3 name of file is l.txt
Segmentation fault (core dumped)
Very strange, as you can see my program dosen't enter my first "if",
but you can see it prints the line before the if statment.
thanks for any help!
I think your problem is not related to your question title "Operator == doesn't work in C". As seen in your output, printf works well and there may be possibly a problem in functions "ZeroPlayersGame" and "TwoPlayersGame". If you gave us more information about these two functions, solving the problem would be easier.
Also, using "1==1" in logical statement is so weird. Why don't you eliminate it and write your statement just after the printf statement. Because "1==1" is always true.

No compiler errors, but there is a bug somewhere

I compiled with "gcc -ansi -pedantic -W -Wall -o ". I only get 2 errors when I compile, and here they are:
easter_eggs.c: In function ‘main’:
easter_eggs.c:23:18: warning: multi-character character constant [-Wmultichar]
if (prompt == 'egg1')
^
easter_eggs.c:23:4: warning: comparison is always false due to limited range of data type [-Wtype-limits]
if (prompt == 'egg1')
when I run the program and hit S, it displays the top 2 printf statements 2 times each. If I type anything and press enter nothing happens it just goes back to the prompt. Even if I type egg1, it still goes back to prompt. Here is the source:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char first_option;
char prompt[16];
system("clear");
system("toilet -f future -F gay Easter Eggs");
printf("\nFind all the easter eggs and you win. Simple enough.\n");
printf("Hit S to start and Q to quit\n");
scanf("%c", &first_option);
if (first_option == 's')
{
while (1)
{
printf("To exit hit Ctrl + C\n");
printf("You must find all easter eggs simply by typing stuff in the prompt below: \n");
memset(prompt, 0, sizeof(prompt));
scanf("%16s", prompt);
getchar();
if (!strcmp(prompt, "egg1"))
{
printf("Found 1\n");
}
}
}
if (first_option == "q")
{
exit(0);
}
else
{
printf("Invalid input. Press Enter to continue\n");
getchar();
main();
}
return 0;
}
Edit 1: I have edited the source
Edit 2: Changed the source again. This time I use strcmp() to compare the strings, not ==
Last Edit: I managed to make it work. Also updated the source so that it works. Thx to all for being patient with me. Havn't slept in idk how many days. :/
Read more about C programming. You are confused about char and strings.
If you want to read a word as a a string of at most 16 bytes with a terminating null byte, use e.g.
char prompt[16];
memset (prompt, 0, sizeof(prompt));
if (scanf("%15s", prompt)<1) return;
if (!strcmp(prompt, "egg1")) {
/// found
Also, you are right to compile with -Wall. But compile also with debugging information and extra warnings:
gcc -Wall -Wextra -g easter_eggs.c -o easter_eggs
and learn how to use the gdb debugger.
Read also the man pages (type man man in your Linux terminal) of scanf(3) & strcmp(3)
When you compare a char variable, you have to compare it with a char.
As the compiler told you, you have a multi-character here.
strcmp() will help you.
As mentioned in other comments, Read C. Below are some suggestions
To store string in C, You must use char[] or char * after allocating memory.
You cannot use == operator to compare strings. Use strcmp() instead.

Beginner C programmer having problems with string functions

I'm a C noob, going back to school for my masters in CS so I'm taking some time to ramp up my skills. I wanted to see if anybody could lend some assistance on why I'm having problems compiling the following code. I've been following the videos on WiBit.net and develop on a 64 bit Linux environment (Ubuntu 13.10). I am using gedit and the gcc compiler no IDE.
This code runs on my Win 7 VM without errors, however when I try to execute it on my host Linux environment I'm getting errors:
Source Code: This example calls the strcmp and strcmpi functions
#include <stdio.h>
#include <string.h>
int main()
{
char str1[255];
char str2[255];
printf("str1: "); gets(str1);
printf("str2: "); gets(str2);
if(strcmp(str1, str2) == 0)
printf("Strings match exactly!");
else if(strcmpi(str1, str2) == 0)
printf("Strings match when ignoring case!");
return 0;
}
Error Message (Linux ONLY):
$gcc main.c -o demo -lm -pthread -lgmp -lreadline 2>&1
/tmp/ccwqdQMN.o: In function main':
main.c:(.text+0x25): warning: thegets' function is dangerous and should not be used.
main.c:(.text+0x8f): undefined reference to `strcmpi'
collect2: error: ld returned 1 exit status
Source Code 2: This example uses the strupr and strlwr functions
#include <stdio.h>
#include <string.h>
int main()
{
char str1[255];
char str2[255];
printf("str1: "); gets(str1);
printf("str2: "); gets(str2);
strlwr(str1);
strupr(str2);
puts (str1);
puts (str2);
return 0;
}
Error Message (Linux ONLY):
$gcc main.c -o demo -lm -pthread -lgmp -lreadline 2>&1
/tmp/ccWnIfnz.o: In function main':
main.c:(.text+0x25): warning: thegets' function is dangerous and should not be used.
main.c:(.text+0x57): undefined reference to strlwr'
main.c:(.text+0x6b): undefined reference tostrupr'
collect2: error: ld returned 1 exit status
I would love a detailed explanation if someone is willing to help and not tear me apart haha. I know that for best practices we shouldn't use gets due to buffer overflow (for example the user enters a 750 character string). Best practices would use fgets instead but my question is whether I'm getting these errors because these functions aren't part of ANSI C or what. They do show up in the man files on my machine which is throwing me through a loop.
Thanks in advance!
UPDATE:
You guys are awesome. Took all of your advice and comments and was able to revise and make a sample program for string comparison as well as conversion to upper/lower. Glad I was able to get it running on both OSes error free as well.
Sample code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
char str[255];
printf("Enter a string: "); fgets(str,255, stdin);
printf("Here is your original string, my master: %s\n", str);
//Now let's loop through and convert this to all lowercase
int i;
for(i = 0; str[i]; i++)
{
str[i] = tolower(str[i]);
}
printf("Here is a lowercase version of your string, my master: %s\n", str);
//Now we'll loop through and convert the string to uppercase
int j;
for(j = 0; str[j]; j++)
{
str[j] = toupper(str[j]);
}
printf("Here is a uppercase version of your string, my master: %s\n", str);
return 0;
}
strcmpi problem: strcasecmp() is the posix standard and so is it in linux.
strupr and strlwr doesn't exist in glibc, although you can implement them with a single line of code, as this:
c - convert a mixed-case string to all lower case
In the compilation, first you can find a warning, because the gcc doesn't find the functions in the included header. In such cases it thinks they are declared as int funcname(void). But later, while linking, it can't find the exported symbols of this nonexistant functions, and thus it can't create the executable. This second error is what stops the compilation.
There are too many difference in the c apis, although the posix standard handles them, microsoft don't follow it.
As you noted, the gets function is unsafe because it does not perform any boundary checking: you have called it with a 255-character string buffer, but if another program wrote a line longer than 255 characters, it could write data into your process's stack, and thereby cause your process to execute malicious code (or at the very least produce a segmentation fault).
Use fgets instead:
printf("str1: "); fgets(str1, 255, stdin);
printf("str2: "); fgets(str2, 255, stdin);
If you read the error output from the compiler carefully, you'll note that it's not issuing an error on your use of gets but a warning. Your code should still compile and execute if you fix the strcmpi call.

Resources