In C Programming - Absolute Beginner's Guide chapter 18, example 2, the program writes
#include <stdio.h>
#include <stdlib.h>
main ()
{
int i;
char msg[25];
printf("Type up to 25 characters and then press Enter...\n");
for (i = 0; i < 25; i++)
{
msg[i] = getchar();
if (msg[i] == '\n')
{
i--;
break;
}
}
putchar('\n');
for (; i >= 0; i--)
{
putchar(msg[i]);
}
putchar('\n');
return 0;
}
I have 2 questions regarding the program.
msg gets allocated an array of 25 characters and printf tells the user to type up to 25 characters. Shouldn't msg then be allocated an array of 26 characters to accommodate backslash zero?
When the for loop is written like this: for (; i >= 0; i--), what is the start expression?
You are right that a string would need one more byte for the terminator.
But the program never treats it as a string, so that's a moot point.
There is none.
None of the expressions in the C for-loop are obligatory.
As a case-in-point, the idiomatic infinite loop:
for(;;) /* Do things */;
No, since this is not a c string and you know the size of the array, which happens to be 25, and can hold 25 elements.
Nothing is defined in the for loop. We use the variable i, defined at the start of main, and the value it holds is the value we reached when inputting characters.
FWIW, there is a bug in this program if the user inputs more than 25 characters before pressing Enter. In that case, the first for loop ends with the value of i equal to 25. In the second for loop, you will end up accessing msg[25], which is accessing msg out of bounds.
i should be decremented after the for loop, not inside the if (msg[i] == '\n') block.
for (i = 0; i < 25; i++)
{
msg[i] = getchar();
if (msg[i] == '\n')
{
break;
}
}
i--;
Related
I tried to implement a solution for the exercise on the C language of K&R's book. I wanted to ask here if this could be considered a legal "solution", just modifying the main without changing things inside external functions.
Revise the main routine of the longest-line program so it will
correctly print the length of arbitrary long input lines, and as much
as possible of the text.
#include <stdio.h>
#define MAXLINE 2 ////
int get_line1(char s[], int lim)
{
int c, i;
for (i = 0; i < lim - 1 && ((c = getchar()) != EOF) && c != '\n'; i++) {
s[i] = c;
}
if (c == '\n') {
s[i] = c;
i++;
}
s[i] = '\0';
return i;
}
int main()
{
int len;
int max = MAXLINE;
char line[MAXLINE];
int tot = 0;
int text_l = 0;
while ((len = get_line1(line, max)) > 0) {
if (line[len - 1] != '\n') {
tot = tot + len;
}
if (line[1] == '\n' || line[0] == '\n') {
printf("%d\n", tot + 1);
text_l = text_l + (tot + 1);
tot = 0;
}
}
printf("%d\n", text_l);
}
The idea is to set the max lenght of the string considered for the array line ad 2.
For a string as abcdef\n , the array line will be ab. Since the last element of the array is not \n (thus the line we are considering is not over), we save the length up until now and repeat the cycle. We will get then the array made of cd, then ef and at the end we will get the array of just \n. Then the else if condition is executed, since the first element of this array is\n, and we print the tot length obtained from the previous additions. We add +1 in order to also consider the new character \n. This works also for odd strings: with abcdefg\n the process will go on up until we reach g\n and the sum is done correctly.
Outside the loop then we print the total amount of text.
Is this a correct way to do the exercise?
The exercise says to “Revise the main routine,” but you altered the definition of MAXLINE, which is outside of main, so that is not a valid solution.
Also, your code does not have the copy or getline routines of the original. Your get_line1 appears to be identical except for the name. However, a correction solution would use identical source code except for the code inside main.
Additionally, the exercise says to print “as much as possible of the text.” That is unclearly stated, but I expect it means to keep a buffer of MAXLINE characters (with MAXLINE at its original value of 1000) and use it to print the first MAXLINE−1 characters of the longest line.
As part of an assignment, I am supposed to write a small program that accepts an indefinite number of strings, and then print them out.
This program compiles (with the following warning
desafio1.c:24:16: warning: format not a string literal and no format arguments [-Wform
at-security]
printf(words[i]);
and it prints the following characters on the screen: �����8 ���#Rl�. I guess it did not end the strings I entered by using getchar properly with the null byte, and it prints out garbage. The logic of the program is to initiate a while loop, which runs untill I press the enter key \n, and if there are an space, this is a word that will be store in the array of characters words. Why am I running into problems, if in the else statement once a space is found, I close the word[i] = \0, in that way and store the result in the array words?
#include <stdio.h>
#include <string.h>
int main()
{
char words[100][100];
int i,c;
char word[1000];
while((c = getchar()) != '\n')
{
if (c != ' '){
word[i++] = c;
c = getchar();
}
else{
word[i] = '\0';
words[i] == word;
}
}
int num = sizeof(words) / sizeof(words[0]);
for (i = 0; i < num; i++){
printf(words[i]);
}
return 0;
}
Here are some fixes to your code. As a pointer (as mentioned in other comments), make sure to enable compiler warnings, which will help you find 90% of the issues you had. (gcc -Wall)
#include <stdio.h>
#include <string.h>
int main() {
char words[100][100];
int i = 0;
int j = 0;
int c;
char word[1000];
while((c = getchar()) != '\n') {
if (c != ' '){
word[i++] = c;
} else {
word[i] = '\0';
strcpy(words[j++], word);
i = 0;
}
}
word[i] = '\0';
strcpy(words[j++], word);
for (i = 0; i < j; i++) {
printf("%s\n", words[i]);
}
return 0;
}
i was uninitialized, so its value was undefined. It should start at 0. It also needs to be reset to 0 after each word so it starts at the beginning.
The second c = getchar() was unnecessary, as this is done in every iteration of the loop. This was causing your code to skip every other letter.
You need two counters, one for the place in the word, and one for the number of words read in. That's what j is.
== is for comparison, not assignment. Either way, strcpy() was needed here since you are filling out an array.
Rather than looping through all 100 elements of the array, just loop through the words that have actually been filled (up to j).
The last word input was ignored by your code, since it ends with a \n, not a . That's what the lines after the while are for.
When using printf(), the arguments should always be a format string ("%s"), followed by the arguments.
Of course, there are other things as well that I didn't fix (such as the disagreement between the 1000-character word and the 100-character words). If I were you, I'd think about what to do if the user entered, for some reason, more than 1000 characters in a word, or more than 100 words. Your logic will need to be modified in these cases to prevent illegal memory accesses (outside the bounds of the arrays).
As a reminder, this program does not accept an indefinite number of words, but only up to 100. You may need to rethink your solution as a result.
#include <stdio.h>
int main() {
int i;
char arr[100];
for (i = 0; i < 100; i++)
scanf("%c", &arr[i]);
for (i = 0; i < 100; i++) {
if ('a' <= arr[i] && arr[i] <= 'z')
arr[i] =-32;
else
if ('A' <= arr[i] && arr[i] <= 'Z')
arr[i] =+32;
}
printf("%s", arr);
return 0;
}
There was a problem:
You have been given a String consisting of uppercase and lowercase English alphabets. You need to change the case of each alphabet in this String. That is, all the uppercase letters should be converted to lowercase and all the lowercase letters should be converted to uppercase. You need to then print the resultant String to output.
What is wrong with the above code? It is compiling successfully but there is a runtime error.
There are multiple problems in your code:
the main issue is the away you adjust the case: arr[i] =-32; does not decrement arr[i] by 32, but stores 32 into arr[i]. The combined assignment operator is spelled -=. You have the same problem for += in the other case.
Converting lower case to upper case by subtracting 32 works for ASCII, but is not portable to other character sets. Similarly, comparing to 'a' and 'z' works for ASCII, but not for EBCDIC. You should use the functions from <ctype.h>.
you read 100 characters with scanf("%c"...) but you do not check the return value, nor do you null terminate the array. Furthermore, you should read at most one less than the size of the array to leave space for the '\0' byte. As coded, your program invokes undefined behavior at printf("%s", arr); because arr is not null terminated.
Here is a corrected version:
#include <ctype.h>
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF) {
if (isupper(c))
c = tolower(c);
else
if (islower(c))
c = toupper(c);
putchar(c);
}
return 0;
}
The most obvious problem is that you are not null-terminating the string, so when you call printf("%s", arr) the behavior will be unpredictable.
The problem with your code is that it never terminates the string. If you read 100 characters, and then you want to print them with %s in printf, you have to add a null terminator at the end, like this:
char arr[100+1]; // See +1
... // Reading code
arr[100] = '\0';
Note that library functions islower/isupper provide a portable, and a lot more readable, approach to testing character type. Similarly, tolower/toupper provide more information about your intentions to the reader of your code than simply adding and subtracting 32. Moreover, C code that uses these standard functions will work on systems with non-ASCII character encoding.
In order to printf("%s", arr), you need to terminate arr with a null-character.
One way to do it is by:
Declaring char arr[101]
Setting arr[100] = 0
Your code has serveral issues: not-null-terminated input string, unproper lower/uppercase conversion and confusion with =- / -= and =+ / += operators.
Next code is based on yours:
As an alternative to get a null-terminated string it uses fgets() instead of scanf(), just for the example.
Also uses C library functions for avoiding issues with different charsets, simplifing the conditions and for upper/lower case operations.
Edited to improve code quality, as #chqrlie suggested in a comment.
#include <stdio.h>
#include <ctype.h>
int main()
{
int i;
char arr[101];
printf("Enter string: ");
fgets(arr, sizeof(arr), stdin);;
for(i=0;i<strlen(arr); i++)
{
int value = (unsigned char) arr[i]; // to properly use int parameters, as expected by ctype.h next functions
if (isupper(value))
{
arr[i]=tolower(value);
}
else {
if (islower(value))
{
arr[i]=toupper(value);
}
}
}
printf("%s", arr);
return 0;
}
Test it here.
I am new to C as of yesterday and I am trying to create a loop that will take ten characters, then print out how many "a"s are in it. no matter how many "a"s are in the string, it prints out 0. any help would be much appreciated.
#include <stdio.h>
#include <string.h>
int main()
{
char string[10];
int c = 0;
int loop = 0;
printf("Enter a string\n");
gets(string);
for (loop = 0; loop >10; ++loop)
{
if (string[c] = 'a')
{
++c;
}
}
printf("A occurs %d times in the entered string.\n",c);
return 0;
}
I think you should read again how for loop works,
for (loop = 0; loop >10; ++loop)
^^^^^^^^
This condition of yours is false from the beginning, as loop = 0, which is not >10. Hence the for loop is never executed.
Plus, when you are comparing inside the for loop, you are using loop variable to iterate over the characters of string. And, to compare == is used, = is assignment operator. So,
if (string[c] = 'a')
this should be
if (string[loop] == 'a')
In one very good book I read, it is written that to avoid such errors, always use the comparison in the other way, for instance,
if ('a' == string[loop])
Even if you mistype and put = instead of ==, you will get an error.
As a side note, don't use gets() function. It has been deprecated. You can read about the Morris Worm to understand what effects gets() can have.
Very quickly few reviews on your code
/* Change */
for (loop = 0; loop >10; ++loop)
/* To */
for (loop = 0; loop < 10; ++loop)
/* Change */
if (string[c] = 'a')
/* To */
if (string[loop] == 'a')
/* Change */
gets(string);
/* To */
fgets(string, 10, stdin);
Okay so I'm using Kernighan and Ritchie's "The C Programming Language" and I'm on exercise 1.13 and I can't seem to get this right. My program seems to not be printing much. The problem is as follows:
Exercise 1-13. Write a program to print a histogram of the lengths of words in its input. It is easy to draw the histogram with
the bars horizontal; a vertical orientation is more challenging.
Besides the creation of variables, here's my pseudocode for reading the input and storing what I want to store in the array.
Create an array -- in this case, my array is of size 21 (21 elements, from 0 to 20) all assigned a value of 0 initially. It has 21 elements because I'm not going to use words that have more than 20 characters. I realize this is weird given no words have zero characters.
Begin counting characters in input.
If I encounter a space, tab, or newline character (i.e., this means the first word ended), stop.
Depending on how many characters the word had, increment that particular position in the array (i.e., if the word had two characters add 1 to the element at position 2 in the array).
Increment the wordCounter variable -- this variable as it's name indicates keeps track of the number of words that have been "read" in the input.
Continue doing this to each word until EOF is reached.
Here's my pseudocode for printing the histogram (horizontally).
For the first position, print the value stored in the first position of the array (i.e., 0) using tick marks |
Do this for every element in the array.
Here's my code:
#include <stdio.h>
#define SIZEOFWORDSOFLENGTH 21
int main() {
int wordsOfLength[SIZEOFWORDSOFLENGTH];
int c, i, j;
int lengthCounter = 0;
/*Initializing all array elements to 0.*/
for (i = 0; i < SIZEOFWORDSOFLENGTH; i++)
wordsOfLength[i] = 0;
/*Going through the input and counting.*/
while ((c = getchar()) != EOF) {
++lengthCounter;
if (c == ' ' || c == '\t' || c == '\n') {
++wordsOfLength[lengthCounter - 1];
lengthCounter = 0;
}
}
for (i = 0; i < SIZZEOFWORDSOFLENGTH; i++) {
printf("Words of Length %d: ", i);
/*The third argument of the following for loop was previously j = j*/
for (j = 0; j < SIZEOFWORDSOFLENGTH; j++) {
while (j < wordsOfLength[i]) {
printf("|");
/*Was previously j++ instead of break*/
break;
}
}
printf("\n");
}
}
I debugged it by hand but I can't seem to find the problem. Maybe something really simple is going over my head. Also, I know this question has been asked before but I'm not trying to find a solution for the actual problem, I think my pseudocode is right if not somewhat right, I just want to know what's wrong with my code and maybe learn something. Thank you in advance.
As indicated in Ji-Young Park's answer, the reading loop has problems because it uses negative indexes into the array wordsOfLength. I would keep life simple and have wordsOfLength[i] store the number of words of length i, though it effectively wastes wordsOfLength[0]. I would use the macros from <ctype.h> to spot word boundaries, and I'd keep a record of whether I was in a word or not. You get credit for using int c.
int inword = 0;
while ((c = getchar()) != EOF)
{
if (!isspace(c))
lengthCounter++;
else if (inword)
{
wordsOfLength[lengthCounter]++;
lengthCounter = 0;
inword = 0;
}
}
if (inword)
wordsOfLength[lengthCounter]++;
This code is not bamboozled by leading white space in the file. If you think there's any risk of reading 'antidisestablishmentarianism' (28) or 'floccinaucinihilipilification' (29) or other grotesquely long words, you should check on lengthCounter before blindly using it as an index, either dropping overlong words from the count or mapping them all to '20+ characters' class.
Your final triple loop is quite problematic too — it is currently:
for (i = 0; i < SIZZEOFWORDSOFLENGTH; i++) {
printf("Words of Length %d: ", i);
/*The third argument of the following for loop was previously j = j*/
for (j = 0; j < SIZEOFWORDSOFLENGTH; j++) {
while (j < wordsOfLength[i]) {
printf("|");
/*Was previously j++ instead of break*/
break;
}
}
printf("\n");
}
Under my scheme, I'd start with i = 1, but that isn't a major issue. I'd ensure that the first printf() printed for 2 digits to align the output for the counts of words of lengths 10-20.
The inner for loop should be constrained by wordsOfLength[i] rather than SIZEOFWORDSOFLENGTH, and the while loop is redundant (not least because you break it on the first iteration each time). You just need simple nested for loops:
for (i = 1; i < SIZZEOFWORDSOFLENGTH; i++)
{
printf("Words of Length %2d: ", i);
for (j = 0; j < wordsOfLength[i]; j++)
printf("|");
printf("\n");
}
The only issue now is if the maximum value in wordsOfLength is too long for comfort (for example, you've read the entire works of Shakespeare, so some of the words appear thousands of times).
you don't need to substract '1' from lengthCounter in
++wordsOfLength[lengthCounter - '1'];
It should be
++wordsOfLength[lengthCounter];