I came across this strange loop behaviour in C. Here is the code:
char arr[SIZE];
fgets(arr, SIZE, stdin);
char brr[SIZE];
int i;
for(i=0; arr[i] != '\0'; i++){
if(arr[i] != ' ') brr[i] = (arr[i] + shift - 'a')%26 + 'a';
else brr[i] = ' ';
}
brr[i-1] = '\0';
The code is for Caesar cipher. It takes some text from the user and stores it in arr, then encodes it by shifting the characters, and this encoded version is put in brr. So, if user enters 'car' and shift is 2, brr is 'ect'.
The problem is in the last line. Normally, it should be brr[i] = '\0', but for some reason the loop will increase I once more after the condition is wrong. I have tried different combinations and it seems like the problem is somehow related to fgets.
Also, the problem is not specific to for loop, while behaves exactly the same.
Edit: Thanks for all the answers. I see now that I should have taken '\n' into account.
somehow related to fgets.
Always test the return values of input functions.
// fgets(arr, SIZE, stdin);
if (fgets(arr, SIZE, stdin)) {
// process arr[]
...
if user enters 'car' and shift is 2,
This is unlikely to only typed 'car' (3 characters). Certainly the user typed c a r Enter (4 characters) which filled arr[SIZE] with "car\n".
Rather than encode the 4 characters with if(arr[i] != ' '), test if arr[i] is a letter. Research isalpha().
Code could exit the for() loop early if '\n' is detected.
// for(i=0; arr[i] != '\0'; i++){
for(i=0; arr[i] != '\0' && arr[i] != '\n'; i++){
...
}
// brr[i-1] = '\0';
brr[i] = '\0';
Advanced
brr[i-1] = '\0'; is certainly a problem if i==0, possible if the first character read is a null character.
Related
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.
Will it be too much to ask if I pray for an elucidation of the following codes from Line 7 onward? I have difficulty in comprehending how getchar() may differ from gets() or scanf() for the most parts. Why is it important to add an escape sequence, \n with it, when in my belief, the value inputting would be done in a horizontal form(as it is a 1D string)? The increment and then the immediate usage of decrement operator bewilder me too. Also, require help with the strcpy(). :|
If somebody has the time, I implore guidance. Thank you!
main()
{
char st[80], ch, word[15], lngst[15];
int i, l, j;
printf("\n Enter a sentence \n ");
i = 0;
while((st[i++] = getchar()) != '\n');
i--;
st[i] = '\0';
l = strlen(st);
i = 0; j = 0;
strcpy(word," ");
strcpy(lngst," ");
while(i <= l)
{
ch = st[i];
if(ch == ' ' || ch == '\0')
{
word[j] = '\0';
if(strlen(word) > strlen(lngst))
strcpy(lngst, word);
strcpy(word," ");
j = 0;
}
else
{
word[j] = ch;
j++;
}
i++;
}
printf("\n Longest word is %s", lngst);
printf("\n Press any key to continue...");
getch();
}
I can't say why the code is written as it is (there are other input options) but I can address some of your concerns:
Why is it important to add an escape sequence, \n?
This "newline" character is returned by getchar() when you hit the return/enter key (the typical 'signal' used to indicate you've done entering your line of text). Without checking for this, the getchar function would just keep (trying to) read in more characters.
How getchar() may differ from gets() or scanf()?
It is notoriously tricky to read in text that includes spaces using the scanf function (this SO Q/A may help), and the gets function has been declared obsolete (because it's dangerous). One could use fgets(st, 80, stdin) but, like I said, I can't comment on why the code is written exactly like it is.
The increment and then the immediate usage of decrement operator
bewilder me too.
The expression (st[i++] = getchar()) transfers the character read into the st array element indexed by i and afterwards increments the value of i, so the next call to getchar will put its result in the next array element. But, when the \n (newline) character has been read, i will have been incremented, ready for the next character - but there won't be one, so we then reduce it by one after we have finished our while loop.
Also, require help with the strcpy().
The call strcpy(dst, src) will copy all characters in the string src (up to and including the required nul terminator, '\0') into the dst string, replacing anything that is already there.
Feel free to ask for further clarification and/or explanation.
while((st[i++] = getchar()) != '\n');
has the same effect as
while (1) { // "infinite" loop
int tmp = getchar(); // get keypress
st[i] = tmp; // copy to string
i++; // update index
if (tmp == '\n') break; // exit the infinite loop after enter is processed
}
I was working on a program in C to count the number of spaces in a sentence. But I haven't managed to get it to work properly. If I enter something like Hello world 1234 how are you the output I'm getting is 3 when the output expected is 5.
My code is :
//Program to count number of words in a given Sentence
#include <stdio.h>
#include <string.h>
int main()
{
char sent[100];
char sentence[] = {' ', '\0'};
printf("\nEnter a sentence :\n");
gets(sent);
strcat(sentence, sent);
int l = strlen(sentence), i = 0, count = 0, countCh = 0;
printf("%d", l);
char ch, ch1;
for (i = 0; i < (l-1); i++)
{
ch = sentence[i];
if (ch == ' ')
{
ch1 = sentence[i+1];
if (((ch1 >= 'A') && (ch1 <= 'Z'))||((ch1 >= 'a') && (ch1 <= 'z')))
count++;
}
}
printf("\nNo of words is : %d", count);
return 0;
}
I used the same logic in Java and it worked fine. Could someone explain whats going wrong?
The problem in your code is with the definition of sentence. When you leave out the array dimension and initialize it, the size of the array will be determined by the length of the initializer.
Quoting the man page of strcat()
The strcat() function appends the src string to the dest string, overwriting the terminating null byte ('\0') at the end of dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable;
That is, the program will invoke undefined behavior.
This way, sentence has certainly way less memory than it it supposed to hold. Moreover, strcat() is not at all required there.
The correct way to do it will be
Define sentence with a proper dimention, like char sentence[MAXSIZE] = {0};, where MAXSIZE will be a MACRO having the size of your choice.
use fgets() to read the user input.
use isspace() (from ctype.h) in a loop to check for presence of space in the input string.
The following
if (((ch1 >= 'A') && (ch1 <= 'Z'))||((ch1 >= 'a') && (ch1 <= 'z')))
count++;
probably should be
if (ch1 != ' ')
count++;
As now " 12345" would not be counted as word.
Also count counts the spaces, so the word count is one more: hence 3 instead of 5.
Your sentence seems to have had the intention of counting the terminatin NUL.
If you want to count real words containing letters, use a bool state whether current and prior state of being in a letter differ.
As mentioned overflow is possible with your code.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I want to divide a string into strings by whitespaces with pointers. I wrote the code below, but it does not work. Do you have any idea?
char sentence [] = "Thank you very much";
char * words [4]; //number of words
int i=0, charCounter=0, wordCounter=0;
while(sentence[i]){
char temp [5]; //maximum character count
while(sentence[i] != ' ' && sentence[i] != '\0'){
temp[charCounter] = sentence[i];
charCounter++;
i++;
}
temp[charCounter] = '\0';
words[wordCounter] = &temp[0];
wordCounter++;
charCounter = 0;
i++;
}
//there I want to write first word to check
int k;
for(k=0; k<12; k++)
printf("%c ", *(words[0]+k));
I think there isn't too much wrong aside from your output loops:
// write word by word
int k;
for(k=0; k < wordCounter; k++)
printf("%s ", words[k]);
// write first word byte by byte
k;
for(k=0; ((words[0])[k])!=0; k++)
printf("%c", (words[0])[k]);
Check this this code pad example based on your code above.
Only thing I changed was to allocate memory for words and copy the string using strcpy:
words[wordCounter] = malloc(sizeof(char) *(charCounter +1));
strcpy(words[wordCounter], &temp[0]);
Otherwise you assign always the same address (compare wrong example).
char temp[5] not need to save the start address of the word.
like as follows
char sentence [] = "Thank you very much";
char *words[sizeof(sentence) / 2] = {0};
int i=0, wordCounter=0;
while(sentence[i]){
while(sentence[i] == ' '){
++i;//skip space
}
if(sentence[i] == '\0')
break;
words[wordCounter++] = &sentence[i];//set top of word
while(sentence[i] != ' ' && sentence[i] != '\0'){
i++;//skip word
}
}
int k;
for(k=0; k<wordCounter; k++){
while(*words[k] != ' ' && *words[k] != '\0')
printf("%c", *words[k]++);
printf("\n");
}
You are adding a 6th char to an array of size 5!
Thats the error!
Also! You never reset the counter to 0, so as you keep going through words, you keep increasing the index added to temp as well
EDIT: I saw the temp[5]; above the while loop xD my Mistake!\
I believe your error lies in never declaring the temp[] array. In C, you must always provide an array with its size, as well.
Add this the line after you define sentence:
char temp[strlen(sentence)];
Also, a space and whitespace are two very different things.
Not all spaces are literally just a space!
However, to get a more accurate reading of any kind of space, using the function isspace, like so, is a much better practice:
while ((isspace(&sentence[i]) != 0) && (sentence[i] != '\0'))
hope this helps! :)
I have this program in C I wrote that reads a file line by line (each line has just one word), sorts the alphabets, and then displays the sorted word and the original word in each line.
#include<stdio.h>
int main()
{
char line[128];
int i=0;
int j;
int length;
while(fgets(line,sizeof line,stdin) != NULL)
{
char word[128];
for (i=0; line[i] != '\0'; i++)
{
word[i]=line[i];
}
while (line[i] != '\0')
i++;
length=i;
for (i=length-1; i >=0; i--)
{
for (j=0; j<i; j++)
{
if (line[j] > line[i])
{
char temp;
temp = line[j];
line[j] = line[i];
line[i]=temp;
}
}
}
printf("%s %s",line,word);
}
return 0;
}
I'm compiling and running it using the following bash commands.
gcc -o sign sign.c
./sign < sample_file | sort > output
The original file (sample_file) looks like this:
computer
test
file
stack
overflow
The output file is this:
ackst stack
cemoprtu computer
efil file
efloorvw overflow
er
estt test
ter
ter
I'm having two issues:
The output file has a bunch of newline characters at the beginning (ie. about 5-7 blank lines before the actual text begins)
Why does it print 'ter' twice at the end?
PS - I know these are very elementary questions, but I only just started working with C / bash for a class and I'm not sure where I am going wrong.
Problem 1
After this code, the variable line contains a line of text, including the newline character from the end of the string
while(fgets(line,sizeof line,stdin) != NULL)
{
This is why you are getting the "extra" newlines. The ASCII value for newline is less than the ASCII value for 'A'. That is why the newlines end up at the beginning of each string, once you've sorted the characters. E.g. "computer\n" becomes "\ncemoprtu".
To solve this, you can strip the newlines off the end of your strings, after the for-loop
if(i > 0 && word[i-1] == '\n')
{
word[i-1] = '\0';
line[i-1] = '\0';
--i;
}
...
printf("%s %s\n",line,word); /* notice the addition of the newline at the end */
This happens to solve problem 2, as well, but please read on, to see what was wrong.
Problem 2
After the loop
for (i=0; line[i] != '\0'; i++) { /* */ }
The string word will not be null-terminated (except by blind luck, since it is ready random uninitialized memory). This is why you get the "ter", because that is part of the data you left behind when you copied the word "computer" to word.
Problem 3
After the loop
for (i=0; line[i] != '\0'; i++) { /* */ }
The value of line[i] != '\0' will always be false. This means that this code will do nothing
while (line[i] != '\0')
i++;
It might make the problem more obvious if I replace the for-loop and the while-loop with basically identical code, using goto:
i=0;
begin_for_loop:
if(line[i] != '\0')
{
{
word[i]=line[i];
}
i++;
goto begin_for_loop;
}
begin_while_loop:
if(line[i] != '\0')
{
i++;
goto begin_while_loop;
}
(btw, most professional programmers will do anything from laugh to yell at you if you mention using goto :) I only am using it here to illustrate the point)
A tip I find handy is to draw out my arrays, variables etc on a piece of paper, then trace through each line of my code (again, on paper) to debug how it works.