Chapitre 4 : solutions
#
Exemples
#
// This is important when using Visual Studio.
// This is done automagically when using CMake.
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main(void)
{
int year, month, day;
char name1, name2;
int status = 0;
printf("First letter in your first name: ");
status = scanf(" %c", &name1);
printf("First letter in your last name: ");
status = scanf(" %c", &name2);
printf("Your birthdate (jj/mm/aa): ");
status = scanf(" %d/%d/%d", &day, &month, &year);
printf("\nYour initials are %c.%c.\n", name1, name2);
printf("You are born on %d/%d/%d\n", day, month, year);
printf("\nASCII CODE: %c=%d, %c=%d\n", name1, name1, name2, name2);
return 0;
}
#include <stdio.h>
int main(void)
{
char line[80]; // string variable
// NOTE: after display, sets the cursor to the next line
puts("Write a line of text:");
gets(line);
puts("The line variable has the following value:");
puts(line);
const int nbExpectedValues = 3;
int h, m, s;
int status;
do // input with validation
{
printf("\nPlease enter hour (h:m:s): ");
status = scanf(" %d:%d:%d", &h, &m, &s);
// IMPORTANT: fflush(stdin) does not always work!
// It is strongly advised NOT to use it
// fflush(stdin);
// Instead, empty the buffer "manually"
{
int c;
do
{
c = getchar();
} while (c != '\n' && c != EOF);
// BIIIP to let user know when there is a problem
if (status != nbExpectedValues)
{
printf("\a");
}
}
} while (status != nbExpectedValues); // status == 3, then we read 3 inputs so we are ok
printf("\nInput hour is: %d:%d:%d\n", h, m, s);
return 0;
}
1242.1_04.03_PrintfScanf
#
#include <stdio.h>
#include <string.h>
int main(void)
{
char line[80]; // String variable
printf("Input and output characters with getchar/putchar. Use '.' to quit.\n\n");
char ch;
do
{
ch = getchar();
putchar(ch);
} while (ch != '.');
putchar('\n');
// fflush does not always work.
// It is strongly advised NOT to use it
// fflush(stdin);
{
int c;
do
{
c = getchar();
} while (c != '\n' && c != EOF);
}
// NOTE: after display, sets the cursor to the next line
puts("Write a line of text:");
// gets may read too many characters
// gets(ligne);
// fgets also reads the character "\n"
fgets(line, sizeof(line), stdin);
printf("Print all characters in line after fgets:\n");
int i;
for (i = 0; i < strlen(line); i++)
{
printf(" %d : %d\n", i, line[i]);
}
// Find a character
char *p = strchr(line, '\n');
if (p != NULL)
{
*p = 0; // We found a end of line
}
else // If we did not find "\n", then we must flush the stdin buffer
{
int c;
do
{
c = getchar();
} while (c != '\n' && c != EOF);
}
printf("Print all characters in line after fgets,\n");
printf("but after having deleted charactere \\n :\n");
for (i = 0; i < strlen(line); i++)
{
printf(" %d : %d\n", i, line[i]);
}
puts("The line variable has the following value:");
puts(line);
const int nbExpectedValues = 3;
int h, m, s;
int status;
do // input with validation
{
printf("\nPlease enter hour (h:m:s): ");
status = scanf(" %d:%d:%d", &h, &m, &s);
// IMPORTANT: fflush(stdin) does not always work!
// It is strongly advised NOT to use it
// fflush(stdin);
// Instead, empty the buffer "manually"
{
int c;
do
{
c = getchar();
} while (c != '\n' && c != EOF);
// BIIIP to let user know when there is a problem
if (status != nbExpectedValues)
{
printf("\a");
}
}
} while (status != nbExpectedValues); // status == 3, then we read 3 inputs so we are ok
printf("\nInput hour is: %d:%d:%d\n", h, m, s);
return 0;
}
1242.1_04.04_IOErrors
#
#include <stdio.h>
int main(void)
{
char a = 65;
printf("char: %%c: %2c %%d: %11d %%f: %8.3f %%lf: %8.3lf\n", a, a, a, a);
int b = 65;
printf("int : %%c: %2c %%d: %11d %%f: %8.3f %%lf: %8.3lf\n", b, b, b, b);
float c = 65.f;
printf("float: %%c: %2c %%d: %11d %%f: %8.3f %%lf: %8.3lf\n", c, c, c, c);
double d = 65.;
printf("double: %%c: %2c %%d: %11d %%f: %8.3f %%lf: %8.3lf\n", d, d, d, d);
return 0;
}
1242.1_04.96_printf_lf_with_int
#
#include <stdio.h>
void myPrintingFunction(double valueToPrint)
{
printf("%lf\n", valueToPrint);
}
int main(void)
{
int valueToPrint = 42;
// From ISO C Standard:
// " If a conversion specification is invalid, the behavior is undefined.
// If any argument is not the correct type for the corresponding conversion
// specification, the behavior is undefined."
// => so the following line has an undefined behavior because
// we pass %lf as the conversion specification and valueToPrint is an int
// NOTE: printf accepts a variable number of parameters, with variable types.
// => so it does not know in advance the type of the parameter and thus
// cannot cast them to the expected type.
printf("%lf\n", valueToPrint); // Prints 0.000000 with VS
// Here, we still pass an int.
// But myPrintingFunction expects a double so the int parameter is first converted
// into a double and then used in printf.
// => In that case, it works.
myPrintingFunction(valueToPrint); // Prints 42.000000
return 0;
}
1242.1_04.97_scanf_vs_scanf_s
#
// This example shows main differences between scanf and scanf_s
// NOTE that Visual Studio will complain when using scanf alone.
// IMPORTANT: scanf_s is NOT a direct replacement for scanf. Some parameters may be different.
// SEE documentation: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/scanf-s-scanf-s-l-wscanf-s-wscanf-s-l?view=vs-2019
// If you want to force Visual Studio to use scanf, define the following
#define _CRT_SECURE_NO_WARNINGS 1
// For this course, we recommend to use scanf instead of scanf_s and to define the following macro
#include <stdio.h>
int main(void)
{
// According to the documentation:
// "scanf_s and wscanf_s require you to specify buffer sizes for some parameters.
// Specify the sizes for all c, C, s, S, or string control set [] parameters.
// The buffer size in characters is passed as an additional parameter."
// So for %c in particular, you need to specify the size of the buffer, that is 1
// Reading 1 character
char c1 = 'a', c1_s = 'a';
printf("Please enter 2 characters: ");
scanf(" %c", &c1);
// Visual Studio:
// warning C4473: 'scanf_s' : not enough arguments passed for format string
// message: placeholders and their parameters expect 2 variadic arguments, but 1 were provided
// message: the missing variadic argument 2 is required by format string '%c'
// message: this argument is used as a buffer size
// scanf_s("%c", &c1_s);
// NOTE: when reading 1 character only, you get a warning but the result is still consistent.
// However, this is risky and should not be used.
// ==>> So specify buffer size instead
scanf_s(" %c", &c1_s, 1);
printf("Read characters are %c and %c.\n", c1, c1_s);
// Reading several characters with scanf and scanf_s
char c2, c3;
printf("Please enter 4 characters: ");
scanf(" %c %c", &c2, &c3);
char c2_s, c3_s;
// The following will NOT work properly
// scanf_s(" %c %c", &c2_s, &c3_s);
// Instead, specify buffer size after each variable address
scanf_s(" %c %c", &c2_s, 1, &c3_s, 1);
printf("Read characters are %c, %c, %c and %c.\n", c2, c3, c2_s, c3_s);
return 0;
}
1242.1_04.98_IOFloatsAndDoubles
#
#include <stdio.h>
int main(void)
{
float smallFloat = 1.0f;
float bigFloat = 12345678900.0f;
double smallDouble = (double)smallFloat;
double bigDouble = (double)bigFloat;
// PRINTF
// Several supported formats for floats: %f, %e, %E, %g and %G
printf("PRINTF FOR FLOATS\n");
printf("\t%f\n\t%e\n\t%E\n\t%g\n\t%G\n", smallFloat, smallFloat, smallFloat, smallFloat, smallFloat);
printf("\t%f\n\t%e\n\t%E\n\t%g\n\t%G\n", bigFloat, bigFloat, bigFloat, bigFloat, bigFloat);
// Same format for doubles "augmented" with 'l' (since C99)
// NOTE: for printf, formats like %f (et al.) can be used interchangeably with %lf (et al.)
// ==>> DO NOT DO THIS!
printf("PRINTF FOR DOUBLES\n");
printf("\t%lf\n\t%le\n\t%lE\n\t%lg\n\t%lG\n", smallDouble, smallDouble, smallDouble, smallDouble, smallDouble);
printf("\t%lf\n\t%le\n\t%lE\n\t%lg\n\t%lG\n", bigDouble, bigDouble, bigDouble, bigDouble, bigDouble);
// SCANF
// Same formats as for printf but we additionally need to specify whether we are reading a float or a double with 'l' in the format
float fa, fb, fc, fd, fe = 0;
printf("SCANF FOR FLOATS\n");
scanf(" %f %e %E %g %G", &fa, &fb, &fc, &fd, &fe); // <<== DO NOT FORGET THE '&'
printf("\t%f\n\t%e\n\t%E\n\t%g\n\t%G\n", fa, fb, fc, fd, fe);
double da, db, dc, dd, de = 0;
printf("SCANF FOR DOUBLES\n");
scanf(" %lf %le %lE %lg %lG", &da, &db, &dc, &dd, &de); // <<== DO NOT FORGET THE '&'
printf("\t%lf\n\t%le\n\t%lE\n\t%lg\n\t%lG\n", da, db, dd, dd, de);
// COMMON MISTAKES
// Reading a float into a double
printf("MISTAKE: reading a float into a double\n");
scanf(" %f", &da);
printf("\t%f\n", da);
// Reading a double into a float => writing in wrong memory locations
// NOTE: must be ran in Release mode. In Debug mode, VS will add extras "around" the local variables in memory for
// run-time checks
printf("MISTAKE: reading a double into a float\n");
fa = 0, fb = 0, fc = 0;
scanf(" %lf", &fb);
// Here, fc may be changed too
printf("\t%f\n\t%f\n\t%f\n", fa, fb, fc);
// In Debug mode, VS says "Run-Time Check Failure #2 - Stack around the variable 'fa' was corrupted. occurred"
return 0;
}
1242.1_04.99_ScanfBufferOverflow
#
#include <stdio.h>
// IMPORTANT for Visual Studio: execute in RELEASE Mode to avoid additional debug padding around stack variables
int main(void)
{
// IMPORTANT for Visual Studio: variables order on the stack is not guaranteed.
// If we do char a[9] instead, then a and b will be in different order on the stack.
char a[8] = "abcdefg";
char b[8] = "abcdefg";
printf("a is at address: %p\n", a);
printf("b is at address: %p\n", b);
printf("a = %s\n", a);
printf("b = %s\n", b);
scanf("%s", b); // Enter "abcdefg!!!!"
printf("a = %s\n", a);
printf("b = %s\n", b);
return 0;
}
Solutions exercices
#