I'm doing the exercises from C Programming Language, the one where you need to make a function to reverse a line. So I did and it works sometimes. But only some times. With the same test it gives different results. I really don't get it, and would appreciate some help. 3 tries out of 4 it would print around 150 spaces and 1 out of 4 it would print the reversed line just like I wanted, though with some junk in the end for some reason.
I was thinking of doing it with pointers, but couldn't figure them out as of now.
Here's my code:
#include <stdio.h>
void reverse(char theline[150]){
int i, j;
char tmp[150];
for (i = 0; theline[i] != 0; i++){
tmp[i] = theline[i];
}
for (j = 0; i >= 0; j++){
theline[j] = tmp[i];
i--;
}
}
int main() {
char line[150];
char c;
int counter = 0;
do {
counter = 0;
while (((c = getchar()) != '\n') && (c != EOF)) { //one line loop
line[counter] = c;
counter++;
}
if (counter > 80){
reverse(line);
printf("%s\n", line);
}
}
while (c != EOF);
return 0;
}
I compile it with "gcc -g -Wall program -o test" and the compiler doesn't give me any errors or warnings. My OS is Ubuntu and I test it with "./test < longtext.txt". This text file has a few lines of different length.
After this loop
while (((c = getchar()) != '\n') && (c != EOF)) { //one line loop
line[counter] = c;
counter++;
}
the character array line does not contain a string because the stored characters are not appended with the terminating zero character '\0'.
So this loop within the function
for (i = 0; theline[i] != 0; i++){
tmp[i] = theline[i];
}
invokes undefined behavior.
You need to append the array with the terminating zero character '\0'.
But even if the passed character array will containe a string the second for loop
for (i = 0; theline[i] != 0; i++){
tmp[i] = theline[i];
}
for (j = 0; i >= 0; j++){
theline[j] = tmp[i];
i--;
}
writes the terminating zero character '\0' in the first position if the array theline. As a result you will get an empty string.
Also the function shall not use the magic number 150 and an auxiliary array.
Pay attention to that the variable c should be declared as having the type int. In general the type char can behave either as the type signed char or unsigned char depending on compiler options. If it will behave as the type unsigned char then this condition
c != EOF
will always evaluate to true.
Without using standard C string functions the function can be declared and defined the following way
char * reverse( char theline[] )
{
size_t i = 0;
while ( theline[i] != '\0' ) i++;
size_t j = 0;
while ( j < i )
{
char c = theline[j];
theline[j++] = theline[--i];
theline[i] = c;
}
return theline;
}
Here is a demonstration program
#include <stdio.h>
char * reverse( char theline[] )
{
size_t i = 0;
while ( theline[i] != '\0' ) i++;
size_t j = 0;
while ( j < i )
{
char c = theline[j];
theline[j++] = theline[--i];
theline[i] = c;
}
return theline;
}
int main( void )
{
char s[] = "Hello World!";
puts( s );
puts( reverse( s ) );
}
The program output is
Hello World!
!dlroW olleH
Why muck-around with reversing a buffer when you can simply store-up the entered characters as they arrive.
#include <stdio.h>
int main() {
for( ;; ) {
char line[ 150 ];
int c, counter = sizeof line;
line[ --counter ] = '\0';
// NB: EOF is an int, not a char
while( ( c = getchar() ) != '\n' && c != EOF && counter > 0 )
line[ --counter ] = (char)c;
printf( "%s\n\n", line + counter );
counter = sizeof line;
}
return 0;
}
Output:
the quick
kciuq eht
Once upon a time in a land far awy
ywa raf dnal a ni emit a nopu ecnO
I wish I was what I was when I wished I was what I am now.
.won ma I tahw saw I dehsiw I nehw saw I tahw saw I hsiw I
Related
I am trying to write a program that reverses words in a sentence, the code is able to do that but also prints gibberish in between. (see below code for sample)
#include <stdio.h>
#define MAX_VALUE 50
int main(){
char c[MAX_VALUE],
b[MAX_VALUE];
int i = 0, j = 0;
while ((c[i] = getchar()) != '\n'){
i++;
}
for(i = MAX_VALUE; i >= 0; i--){
if (c[i] == ' '){
for(j = i+1; j < MAX_VALUE; j++){
if (c[j] != ' '){
printf("%c", c[j]);
}
else{
break;
}
}
printf(" ");
}
}
while (c[i] != ' '){
printf("%c", c[i]);
i++;
}
}
Loop goes backwards when it detects a space it prints the word until it finds another space then goes backwards again from where it left off last
The input and output expected:
input: test a is this
output: this is a test
What I get:
input: test a is this
output:
this
`����l�,+�D �=� is a test
This for loop
while ((c[i] = getchar()) != '\n'){
i++;
}
can write outside the array c and store the new line character '\n' in the array.
And this output consisting from two lines
this
`����l�,+�D �=� is a test
demonstrates that the new line character was stored in the array.
Also you forgot to append the entered sequence of characters with the zero terminating character '\0' to form a string.
You could write the while loop the following way
int ch;
while ( i < MAX_VALUE - 1 && ( ch = getchar() ) != '\n' && ch != EOF ){
c[i++] = ch;
}
c[i] = '\0';
Or if you want store the entered sequence without the terminating zero character '\0' then the loop can look like
int ch;
while ( i < MAX_VALUE && ( ch = getchar() ) != '\n' && ch != EOF ){
c[i++] = ch;
}
In this case the variable i will contain the number of entered symbols in the array and you should use its value instead of the value MAX_VALUE in the following loops.
This outer for loop
for(i = MAX_VALUE; i >= 0; i--){
is incorrect because the user can enter a sequence of symbols that contains less than MAX_VALUE symbols. You should either use standard string function strlen (if you appended the sequence with the terminating zero character '\0') to determine the length of the string stored in the array or the value of the variable i as mentioned above that denotes the number of entered symbols.
And it is not enough to check this condition
if (c[i] == ' '){
because the leading spaces can be absent in the entered string. So you need to check also whether i is equal to 0. Otherwise the output can be incorrect if the sequence contains for example only one word.
The inner for loop
for(j = i+1; j < MAX_VALUE; j++){
again is incorrect by the same reason of using MAX_VALUE in the condition.
Pay attention to that the array b
char c[MAX_VALUE],
b[MAX_VALUE];
is not used in your program.
Using your approach I can suggest the following solution to output words of a string in the reverse order shown in the demonstrative program below.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main( void )
{
const char *s = "test a is this";
for( size_t i = strlen( s ); i != 0; )
{
while ( i != 0 && isblank( ( unsigned char )s[i-1]) )
{
putchar( s[--i] );
}
size_t j = i;
while ( j != 0 && !isblank( ( unsigned char )s[j-1]) )
{
--j;
}
if ( j != i )
{
size_t last = i;
i = j;
while ( j != last )
{
putchar( s[j++] );
}
}
}
putchar( '\n' );
}
The program output is
this is a test
The code uses two arrays and two 'counters', and fiddles around with individual characters one-at-a-time. It's easy to get lost and use an upper bound that is outside the array size.
Simplify! This "reversal" is an excellent example of when recursion should be the go-to method of solving the problem.
#include <stdio.h>
#include <string.h>
void output( char *p ) {
if( (p = strtok( p, " " )) == NULL ) return;
output( NULL );
printf( "%s ", p );
}
int main() {
char str[] = "The quick brown fox jumps over the dogs";
output( str );
return 0;
}
dogs the over jumps fox brown quick The
Some purists may want an entire buffer to be assembled before printing. This resulting string includes an invisible SP at the end that could be lopped off if desired.
#include <stdio.h>
#include <string.h>
char *revWords( char *dst, char *p ) {
if( (p = strtok( p, " " )) == NULL ) return NULL;
revWords( dst, NULL );
return strcat( strcat( dst, p ), " " );
}
int main() {
char str[] = "The quick brown fox jumps over the dogs";
char buf[sizeof str + 1 + 1] = { 0 }; // important to initialise
puts( revWords( buf, str ) );
return 0;
}
For an alternative, here's a version without recursion. It requires, like above, a mutable buffer holding the string.
#include <stdio.h>
#include <ctype.h>
int main() {
char str[] = " The quick brown fox jumps over the dogs ";
int i = 0;
// note: 1 string buffer, 1 index variable
for( i = 0; str[i]; i++ ) ; // loop
while( i >= 0 ) {
while( i >= 0 && !isalnum( str[ i ] ) ) str[i--] = '\0';
while( i >= 0 && isalnum( str[ i ] ) ) i--;
printf( "%s ", str + i + 1 );
}
puts( "" );
return 0;
}
I wrote code to reverse an array after in C.
I'm using C17. In the code the user is asked to input a word, the word then is put into an array
and then reversed.
The code works for the exception that it adds some random characters and I couldn't figure out why it does that.
Can you help me with that?
Here is my code
#include <stdio.h>
#define MAXLINE 80
void inputtoarray(char input[]); //Take the input from user and put it into an array
void reverseinput(char input1[]);
int main(){
char input[MAXLINE];
inputtoarray(input);
reverseinput(input);
return 0;
}
void inputtoarray(char input[]){
int c; //to hold the indiviual characters before going into the array
//int was used over char because I want to be able to hold EOF
int i; //i is the array counter
//ask the user to type in a word
printf("Please type in a word:\n");
for(i=0; (c=getchar()) != '\n'; ++i){
input[i] = c;
}
}
void reverseinput(char input1[]){
int cinput;
int coutput;
char temp[MAXLINE]; //define a temporary array
//count the number of characters in the array
for (cinput=0; input1[cinput] != '\0'; ++cinput){
}
coutput=cinput;
//the reversing process. Here cinput holds the number of the last character
for (cinput=0; coutput > 0; --coutput, ++cinput ){
temp[coutput] = input1[cinput];
//input1[coutput] = temp[coutput];
//printf("%s", temp);
}
input1 = temp;
printf("%s", input1);
}
The function inputtoarray does not input a string. As a result this loop
for (cinput=0; input1[cinput] != '\0'; ++cinput){
}
within the function reverseinput results in undefined behavior.
The function inputtoarray can look for example the following way
void inputtoarray( char input[], size_t n )
{
int c; //to hold the indiviual characters before going into the array
//int was used over char because I want to be able to hold EOF
size_t i = 0; //i is the array counter
//ask the user to type in a word
printf("Please type in a word:\n");
for ( ; i + 1 < n && ( c = getchar() ) != EOF && c != '\n'; ++i )
{
input[i] = c;
}
input[i] = '\0';
}
and called like
inputtoarray( input, MAXLINE );
Moreover this loop
for (cinput=0; coutput > 0; --coutput, ++cinput ){
temp[coutput] = input1[cinput];
//input1[coutput] = temp[coutput];
//printf("%s", temp);
}
does not set the element temp[0] due to the condition coutput > 0. So the first element of the array temp has an indeterminate value.
And this assignment
input1 = temp;
does not make a sense because it changes the local variable input instead of changing the array pointed to by the pointer (parameter) input.
Without using standard string functions the program can look the following way.
#include <stdio.h>
#define MAXLINE 80
void inputtoarray( char input[], size_t n )
{
int c; //to hold the indiviual characters before going into the array
//int was used over char because I want to be able to hold EOF
size_t i = 0; //i is the array counter
//ask the user to type in a word
printf("Please type in a word:\n");
for ( ; i + 1 < n && ( c = getchar() ) != EOF && c != '\n'; ++i )
{
input[i] = c;
}
input[i] = '\0';
}
void reverseinput( char input[] )
{
size_t n = 0;
while ( input[n] ) ++n;
if ( n != 0 )
{
for ( size_t i = 0; i < --n; i++ )
{
char c = input[i];
input[i] = input[n];
input[n] = c;
}
}
}
int main(void)
{
char input[MAXLINE];
inputtoarray( input, MAXLINE );
reverseinput( input );
puts( input );
return 0;
}
Its output might look like
Please type in a word:
Hello
olleH
I'm trying to solve exercise 1-19 in K&R C second edition. "Write a function reverse that reverses the character string s. Use it to write program that reverses its input a line at a time."
My solution takes two input strings s and t. s is source and t is target. And it copies the data in source s to t. I'm able to solve the problem, but I'm struggling hard to understand why would source string s be modified, even though it is not on the left hand side of the equal operator.
#include <stdio.h>
/* Solution to Exercise 1-19. Chapter 1 */
#define MAXLENGTH 10
int getln(char s[], int lim);
void reverse(char s[], char t[]);
int main()
{
int i, len;
char s[MAXLENGTH]; /* original string */
char t[MAXLENGTH]; /* reversed string */
while ((len = getln(s, MAXLENGTH)) > 0) {
printf("before reverse: %s", s);
reverse(s,t);
printf("reversed string: %s\n", t);
printf("after reverse: %s", s);
}
return 0;
}
/* getln: read a line into s, return length */
int getln(char s[], int lim)
{
int c, i, l;
l = 0;
for (i = 0; ((c = getchar()) != EOF) && (c != '\n'); ++i) {
if (i < (lim - 1)) {
s[l] = c;
++l;
}
}
if (c == '\n') {
s[l] = c;
++l;
}
s[l] = '\0';
return l;
}
/* reverse: reverses s to target t */
void reverse(char s[], char t[])
{
int i, j;
for (i = 0; s[i] != '\0'; ++i)
;
--i;
if (s[i] == '\n') {
--i;
}
for (j = 0; i >= 0; ++j) {
t[j] = s[i];
--i;
}
t[j] = '\0';
}
Test case:
$ ./a.out < testdata
before reverse: abcdefghi
reversed string: ihgfedcba
after reverse: abcdefghi
ihgfedcba$
Contents of file testdata:
$ cat testdata
abcdefghijklmnopqrstuvwxyz
$
There is a bug in the function getln To simplify the analyze of the function let's assume that lim is equal to 2.
Then in this loop
l = 0;
for (i = 0; ((c = getchar()) != EOF) && (c != '\n'); ++i) {
if (i < (lim - 1)) {
s[l] = c;
++l;
}
}
you can write lim-1 characters that is only one character. The loop stops its iterations when the user will press the key Enter that sends to the input buffer the new line character '\n'.
So the last read character is the new line character '\n'. This character is stored in the string after the loop
if (c == '\n') {
s[l] = c;
++l;
}
Now the limit is exhausted. Two characters of the passed character array are set.
However in the next statement
s[l] = '\0';
there is access to the memory beyond the limit when l is equal to 2.
That is all. The function invokes undefined behavior provided that the value of the parameter lim is equal to the size of the passed character array. The terminating zero character '\0' is written in the memory outside the character array and later can be overwritten.
I would define the function the following way as it is shown in the demonstrative program below.
#include <stdio.h>
size_t getln( char s[], size_t n )
{
size_t i = 0;
if ( n )
{
int c;
while ( i + 1 < n && ( c = getchar() ) != EOF && c != '\n' )
{
s[i++] = c;
}
if ( c == '\n' && i + 1 < n ) s[i++] = c;
s[i] = '\0';
}
return i;
}
int main(void)
{
enum { N = 10 };
char s[N];
while ( getln( s, N ) ) printf( "\"%s\"\n", s );
return 0;
}
If to enter
abcdefghijklmnopqrstuvwxyz
then the program output will be
"abcdefghi"
"jklmnopqr"
"stuvwxyz
"
That is only the last entered string contains the new line characters.
Pay attention to that in the exercise there is written
Write a function reverse that reverses the character string s.
This means that you need to reverse the original string itself instead of coping it in the reverse order to another character array.
Such a function can look the following way
#include <stdio.h>
char * reverse( char *s )
{
size_t n = 0;
while ( s[n] != '\0' ) n++;
if ( n && s[n-1] == '\n' ) --n;
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n-i-1];
s[n-i-1] = c;
}
return s;
}
size_t getln( char s[], size_t n )
{
size_t i = 0;
if ( n )
{
int c;
while ( i + 1 < n && ( c = getchar() ) != EOF && c != '\n' )
{
s[i++] = c;
}
if ( c == '\n' && i + 1 < n ) s[i++] = c;
s[i] = '\0';
}
return i;
}
int main(void)
{
enum { N = 10 };
char s[N];
while ( getln( s, N ) ) printf( "\"%s\"\n", reverse( s ) );
return 0;
}
Again if the input is
abcdefghijklmnopqrstuvwxyz
then the program output is
"ihgfedcba"
"rqponmlkj"
"zyxwvuts
"
If you want to remove the new line character '\n' from the string inside the function reverse then substitute this statement
if ( n && s[n-1] == '\n' ) --n;
for this one
if ( n && s[n-1] == '\n' ) s[--n] = '\0';
You are not allocating memory for c or t, therefore you are overwriting things.
I was trying to write a program that reverses its input a line at a time. I thought I had done it successfully, however it sometimes doesn't give the desirable output (this happens when I put an input with a smaller length than the one I put previously). I am new to this and I was wondering what can I do to solve this issue.
Program:
#include <stdio.h>
#define MAXLINE 1000
void reverse(char o[], char l[]);
int mgetline(char line[]);
int main(void){
int len;
char line[MAXLINE];
char rev[MAXLINE];
while((len = mgetline(line)) > 0){
reverse(rev, line);
printf("%s\n",rev);
}
return 0;
}
int mgetline(char s[])
{
int c,i;
for(i = 0; ((c=getchar())!=EOF) && (c!='\n'); ++i)
s[i] = c;
if (c == '\n')
{
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
void reverse(char revi[], char liner[])
{
int i, c, j;
for(i=0;liner[i]!='\0';++i)
;
--i;
if(liner[i]=='\n')
--i;
for(j=0; j<=i ; ++j){
c = i - j;
revi[j] = liner[c];
}
--j;
}
Since you not terminating the revi string at the end, therefore it will print the leftout characters from the previous result if the new input is smaller. Fix it by adding this
revi[j] = '\0';
at the end of the reverse function and delete that last --j;.
The function reverse does not build a string that is it does not append the terminating zero '\0' to the result string.
The second parameter of the function should have the qualifier const because it is not changed in the function.
As all standard C string functions this function should return pointer to the result string.
And it is better to name the function like reverse_copy instead of reverse because the name reverse is usually used when a container is reversed "in place".
It can look the following way
char * reverse_copy( char revi[], const char liner[] )
{
size_t n = 0;
while ( liner[n] ) ++n;
if ( n != 0 && liner[n-1] == '\n' ) --n;
size_t i = 0;
while ( n != 0 ) revi[i++] = liner[--n];
revi[i] = '\0';
return revi;
}
I'm very new to C and I'm trying to write a program that checks if a string contains any uppercase letters, and if it does, prints them out. I'm using https://www.onlinegdb.com/online_c_compiler# as my compiler (cause I don't have access to my personal computer right now) and after a test run, the results are (p.s. I know gets isn't safe):
main.c:16:5: warning: ‘gets’ is deprecated [-Wdeprecated-declarations]
/usr/include/stdio.h:638:14: note: declared here
main.c:(.text+0x26): warning: the `gets' function is dangerous and should not be used.
sTrInG
Contains Uppercase!
Uppercase Letters:0
...Program finished with exit code 0
Press ENTER to exit console.
In this case, I expect an output something like this:
Contains Uppercase!
Uppercase Letters: TIG
My script:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main()
{
char str[100];
gets(str);
int containsUpper = 0;
char upperLetters[100] = {0};
for (int i=0; i < strlen(str); i++) {
if (islower(str[i])) {
continue;
} else {
containsUpper = 1;
upperLetters[i] = str[i]; // is this the bad line?
}
}
if (containsUpper) {
printf("Contains Uppercase!\n");
printf("Uppercase Letters:");
printf("%zu\n", strlen(upperLetters)); // prints 0 so upperLetters is empty..?
for (int i=0; i < strlen(upperLetters); i++) {
printf("%c", upperLetters[i]);
}
} else {
printf("Does not contain Uppercase!");
}
return 0;
}
This loop
for (int i=0; i < strlen(str); i++) {
if (islower(str[i])) {
continue;
} else {
containsUpper = 1;
upperLetters[i] = str[i]; // is this the bad line?
}
}
1) is incorrect and 2) suffers from a bad style of programming.
You should append upper case letters to the character array upperLetters
consistently that you are not doing. Also if a character is not a lower case character it does not mean that the character is an upper case character. For example in general it can be a digit or a punctuation.
Also there is no need to call the function strlen. An argument of the function call should be cast to unsigned char. Otherwise it can occur that a call of the function will invoke undefined behavior.
The part of the loop with the continue statement is redundant.
The loop can look for example the following way
for ( size_t i = 0, j = 0; str[i] != '\0'; i++ )
{
if ( isupper( ( unsigned char )str[i] ) )
{
upperLetters[j++] = str[i];
}
}
containsUpper = upperLetters[0] != '\0';
If you need the number of uppercase letters in other part pf the program then the loop can look like
size_t n = 0;
for ( size_t i = 0; str[i] != '\0'; i++ )
{
if ( isupper( ( unsigned char )str[i] ) )
{
upperLetters[n++] = str[i];
}
}
if ( n )
{
printf( "Contains Uppercase!\n" );
printf( "Uppercase Letters: " );
printf("%zu\n", n );
for ( size_t i = 0; i < n; i++ )
{
printf( "%c", upperLetters[i] );
}
//…
Or instead of the loop
for ( size_t i = 0; i < n; i++ )
{
printf( "%c", upperLetters[i] );
}
you could just write
printf( "%s\n", upperLetters );
because the array was zero-initialized and as such it contains a string.
As the compiler reported the function gets is unsafe and is not supported by the C Standard. Instead use the function fgets.
For example
fgets( str, sizeof( str ), stdin );
I wouldn't consider numbers or characters like !?#%& to be uppercase letters, yet your program counts them as such. You absolutely must not use gets, but there is no reason in this case to replace it with fgets since your program is not fundamentally line-oriented. You simply don't care about lines. Just do:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int
main(void)
{
int c;
char upperLetters[100] = {0};
unsigned k = 0;
while( ( c = getchar()) != EOF && k < sizeof upperLetters ) {
if( isupper(c)) {
upperLetters[k++] = c;
}
}
if (k) {
puts("Contains Uppercase!");
printf("Uppercase Letters: %u\n%s\n", k, upperLetters);
} else {
fprintf(stderr, "Does not contain Uppercase!");
}
return k != 0;
}
(Note that the original program only looks at the first line of input. Whether that is a bug or intentional is not clear. If it is intentional, add a check and break out of the loop when after the first newline character is read.)
You want the loop to be:
int i, j=0;
for (i=0; i < strlen(str); i++) {
if (isupper((unsigned char)str[i])) {
upperLetters[j++] = str[i];
}
}
upperLetters[j]= '\0';
containsUpper = (j>0);
That is, keep a separate index of the upper letters array. And don't forget to terminate it.
A better way for the loop is:
int i, j, k;
for (i=0, j=0, k=strlen(str); i < k; i++) {
as this calls strlen only once.
EDIT: As user LxerLx pointed out, a character which is not a lower case letter does not have to be an upper case letter. I updated the loop for this.