K&R2 exercise 1.19 "reversing a character array"

A

arnuld

i have created a solutions myself. it compiles without any trouble
and runs but it prints some strange characters. i am not able to find
where is the trouble.


--------------------------------- PROGRAMME
--------------------------------
/* K&R2 section 1.9
exercise 1.19

STATEMENT: write a function "reverse(s)" that reverses the character
string "s". use it to to write a programme that reverses
its input a line at a time.


it works like this:

1.) "main" takes input from user and creates a char array from that.
2.) then "main" calls "reverse_them" to reverse the char array it
created.
3.) "reverse_them", 1st, calls "arr_size" on the array "main" created.
4.) 2nd, "reverse them", then revrses the characters of 1st array by
putting
the array into in a 2nd array(a new array) in reverse order.

*/

#include <stdio.h>

#define MAXLINE 1000

int arr_size(char arr[]);
void reverse_them(char to[], char from[]);

int main(void) {

char my_array[MAXLINE];
char reversed_array[MAXLINE];
int i, c;

/* now we will take some input and feed it into array */
for(i = 0; ((c = getchar()) != EOF) && i < MAXLINE; ++i)
my_array = c;

my_array = '\0'; /* '\0' is required in the end */

printf("array size: %d\n", arr_size(my_array));
reverse_them(my_array, reversed_array);

return 0;
}


/* this function "reverses:" the 1st array into 2nd */

void reverse_them(char from[], char to[])
{
int i, asize, li;

asize = arr_size(from); /* get input array size */
li = asize - 1; /* because of last '\0' element */

for(i = 0; (to[li] = from) != '\0'; ++i)
--li;


printf("\nthe original input: %s\n", from);
printf("reversed input: %s\n", to);
}



/* this function gets the size of an array */

int arr_size(char ar[])
{
int i;

for(i = 0; (ar != '\0') == 1; ++i)
;

return i;
}
------------------------------- OUTPUT -----------------------
[arch@voodo kr2]$ ./a.out
like this


K&R2
array size: 17

the original input: like this


K&R2

reversed input:
2R&K


siht ekil???
[arch@voodo kr2]$
 
S

santosh

arnuld said:
i have created a solutions myself. it compiles without any trouble
and runs but it prints some strange characters. i am not able to find
where is the trouble.

--------------------------------- PROGRAMME
--------------------------------
/* K&R2 section 1.9
exercise 1.19

STATEMENT: write a function "reverse(s)" that reverses the character
string "s". use it to to write a programme that reverses
its input a line at a time.

it works like this:

1.) "main" takes input from user and creates a char array from that.
2.) then "main" calls "reverse_them" to reverse the char array it
created.
3.) "reverse_them", 1st, calls "arr_size" on the array "main" created.
4.) 2nd, "reverse them", then revrses the characters of 1st array by
putting
the array into in a 2nd array(a new array) in reverse order.
*/

#include <stdio.h>

#define MAXLINE 1000

int arr_size(char arr[]);

A better return type would be unsigned or size_t.
void reverse_them(char to[], char from[]);

int main(void) {
char my_array[MAXLINE];
char reversed_array[MAXLINE];
int i, c;

/* now we will take some input and feed it into array */
for(i = 0; ((c = getchar()) != EOF) && i < MAXLINE; ++i)
my_array = c;

my_array = '\0'; /* '\0' is required in the end */


If the for loop breaks because the maximum array length was reached,
your subsequent suffix of a null character will write to memory beyond
the array. To fix it, store at most MAXLINE - 1 characters into the
array.
printf("array size: %d\n", arr_size(my_array));
reverse_them(my_array, reversed_array);

If reverse array is to be reusable function, it should not attempt to
print the output. Rather that task should be delegated to the calling
function, (in this case main.)

Also, since you've already computed your string's length before the
call to reverse_them, you could just pass the value into reverse_them
instead of calling arr_size again inside reverse_them.
return 0;
}

/* this function "reverses:" the 1st array into 2nd */
void reverse_them(char from[], char to[])
{
int i, asize, li;

asize = arr_size(from); /* get input array size */
li = asize - 1; /* because of last '\0' element */

for(i = 0; (to[li] = from) != '\0'; ++i)
--li;


This is a very compilcated way of doing it. I would simply do it as:

i = 0;
while ( to[li--] = from[i++] );
printf("\nthe original input: %s\n", from);
printf("reversed input: %s\n", to);
}

/* this function gets the size of an array */
int arr_size(char ar[])
{
int i;

for(i = 0; (ar != '\0') == 1; ++i)


Simply writing ar != '\0' would do.
;
return i;

Here you're returning the length of the string in ar _including_ the
terminating null character, unlike the Standard library's strlen.

Your program seems to work fine here.
 
B

Barry Schwarz

i have created a solutions myself. it compiles without any trouble
and runs but it prints some strange characters. i am not able to find
where is the trouble.


--------------------------------- PROGRAMME
--------------------------------
/* K&R2 section 1.9
exercise 1.19

STATEMENT: write a function "reverse(s)" that reverses the character
string "s". use it to to write a programme that reverses
its input a line at a time.


it works like this:

1.) "main" takes input from user and creates a char array from that.
2.) then "main" calls "reverse_them" to reverse the char array it
created.
3.) "reverse_them", 1st, calls "arr_size" on the array "main" created.
4.) 2nd, "reverse them", then revrses the characters of 1st array by
putting
the array into in a 2nd array(a new array) in reverse order.

*/

#include <stdio.h>

#define MAXLINE 1000

int arr_size(char arr[]);
void reverse_them(char to[], char from[]);

int main(void) {

char my_array[MAXLINE];
char reversed_array[MAXLINE];
int i, c;

/* now we will take some input and feed it into array */
for(i = 0; ((c = getchar()) != EOF) && i < MAXLINE; ++i)
my_array = c;

my_array = '\0'; /* '\0' is required in the end */


Let's assume the input was abc followed by EOF. At this point,
my_array contains 'a', 'b', 'c', and '\0'
printf("array size: %d\n", arr_size(my_array));

arr_size returns 3.
reverse_them(my_array, reversed_array);

return 0;
}


/* this function "reverses:" the 1st array into 2nd */

void reverse_them(char from[], char to[])
{
int i, asize, li;

asize = arr_size(from); /* get input array size */

asize is now 3.
li = asize - 1; /* because of last '\0' element */

li is now 2.
for(i = 0; (to[li] = from) != '\0'; ++i)
--li;


In iteration 1, li is 2, i is 0, and to[2] is set to 'a'.

In iteration 2, li is 1, i is 1, and to[1] is set to 'b'.

In iteration 3, li is 0, i is 2, and to[0] is set to 'c'.

In iteration 4, li is -1, i is 3, and you attempt to set to[-1] to
'\0'. This invokes undefined behavior.

Once you fix the for loop so it doesn't attempt to store into a
nonexistent member of to, you still have the problem that the contents
of to are not a string because they are not terminated with a '\0' in
to[3]. It contains 'c', 'b', 'a', and a number of indeterminate
(uninitialized) values.
printf("\nthe original input: %s\n", from);
printf("reversed input: %s\n", to);
}



/* this function gets the size of an array */

int arr_size(char ar[])
{
int i;

for(i = 0; (ar != '\0') == 1; ++i)


The second clause is no different than
ar != '\0';
which is simpler, more common, and easier to understand.
;

return i;
}
------------------------------- OUTPUT -----------------------
[arch@voodo kr2]$ ./a.out
like this


K&R2
array size: 17

the original input: like this


K&R2

reversed input:
2R&K


siht ekil???
[arch@voodo kr2]$


Remove del for email
 
A

arnuld

int arr_size(char arr[]);
A better return type would be unsigned or size_t.

i chose "int" because:

1.) C FAQs advise to use "int".

2.) all signed and unsigned types are guarnteed to have same size:


http://c-faq.com/decl/inttypes.html


If the for loop breaks because the maximum array length was reached,
your subsequent suffix of a null character will write to memory beyond
the array. To fix it, store at most MAXLINE - 1 characters into the
array.

done


If reverse array is to be reusable function, it should not attempt to
print the output. Rather that task should be delegated to the calling
function, (in this case main.)

you are right on this but how will "reverse_them" will return an
array ? i am on chapter 1 and all return types i see are "int", "char"
or "float".

Also, since you've already computed your string's length before the
call to reverse_them, you could just pass the value into reverse_them
instead of calling arr_size again inside reverse_them.

this will introduce one more variable into the programme:

int j;

j = arr_size(my_array)

then i can use "j" at 2 places i used "arr_size(my_array)"

what is the benefit of introducing an extra variable ?

This is a very compilcated way of doing it. I would simply do it as:

i = 0;
while ( to[li--] = from[i++] );

i did so and got this warning message:


[arch@voodo kr2]$ gcc -Wall -Wextra 19-ex-1-19.c
19-ex-1-19.c: In function 'reverse_them':
19-ex-1-19.c:57: warning: suggest parentheses around assignment used
as truth value
[arch@voodo kr2]$

for(i = 0; (ar != '\0') == 1; ++i)


Simply writing ar != '\0' would do.
done
;
return i;

Here you're returning the length of the string in ar _including_ the
terminating null character, unlike the Standard library's strlen.


"i" is integer only. it has nothing to do with '\0'.
Your program seems to work fine here.

thanks :)
 
S

santosh

arnuld said:
int arr_size(char arr[]);
A better return type would be unsigned or size_t.

i chose "int" because:

1.) C FAQs advise to use "int".

2.) all signed and unsigned types are guarnteed to have same size:

Not at all. A char is always one byte, which may be eight bits or
more. The exact value for an implementation is specified by the macro
CHAR_BIT. It has to be at least eight. A short should be at least as
big or bigger than a char. An int should be >= to a short, but must be
at least 16 bits. A long must be >= an int and must be a minimum of 32
bits. A long long type must be >= a long and at least of 64 bits.
Other types are derived from these basic types.

This is a C99 header that specifies various macros for portably using
printf and scanf family of functions with the extended integer types
in stdint.h.

you are right on this but how will "reverse_them" will return an
array ? i am on chapter 1 and all return types i see are "int", "char"
or "float".

IIRC, both your arrays are local to the calling function, (which in
your case is main); you're simply passing pointers to their first
element to the reverse function. So you can print the reversed string
from main.

It's generally a good programming practise to delegate user interface
and other "higher-level" decisions to higher level functions. Lower
level functions should generally perform their allotted task and
return.
this will introduce one more variable into the programme:

int j;

j = arr_size(my_array)

then i can use "j" at 2 places i used "arr_size(my_array)"

what is the benefit of introducing an extra variable ?

An extra variable, especially so simple a one as an int, is
computationally, far less expensive than an extra function call. Since
you know that the string does not change between the two points,
scanning for it's length again is redundant and with long strings,
could become noticeably slower.
This is a very compilcated way of doing it. I would simply do it as:

i = 0;
while ( to[li--] = from[i++] );

i did so and got this warning message:

[arch@voodo kr2]$ gcc -Wall -Wextra 19-ex-1-19.c
19-ex-1-19.c: In function 'reverse_them':
19-ex-1-19.c:57: warning: suggest parentheses around assignment used
as truth value

gcc is warning because of a very common mistake newbies make, writing:

while(x = y)

when they meant

while(x == y)

In our case, the warning is not applicable, since we _did_ mean to
assign rather than compare for equality.

PS. Barry spotted an error I didn't. Be sure to read his post
elsethread.
 
A

arnuld

ok this is what, finally, i have got and it works

:-(

because i *cheat* by using /char*/ in creating the solution. at
chapter 1 i am not supposed to use /char*/.

can nybody do the same without using /pointers/ ?


--------------- PROGRAMME -------------------------
/* K&R2 section 1.9
exercise 1.19

STATEMENT: write a function "reverse(s)" that reverses the character
string "s" use it to to write a programme that reverses
its input a line at a time.


it works like this:

1.) "main" takes input from user and creates a char array from that.
2.) then "main" calls "reverse_them" to reverse the char array it
created.
3.) "reverse_them", 1st, calls "arr_size" on the array "main" created.
4.) 2nd, "reverse them", then revrses the characters of 1st array by
putting
the array into in a 2nd array(a new array) in reverse order.

*/

#include <stdio.h>

#define MAXLINE 1000

int arr_size(char arr[]);
char* reverse_them(char to[], char from[]); /* declarations first */

int main(void) {

char my_array[MAXLINE];
char reversed_array[MAXLINE];
int i, c;

/* now we will take some input and feed it into array */
for(i = 0; ((c = getchar()) != EOF) && i < MAXLINE - 1; ++i)
my_array = c;

my_array = '\0'; /* '\0' is required in the end */

printf("array size: %d\n", arr_size(my_array));

printf("%s\n", reverse_them(my_array, reversed_array));


return 0;
}


/* this function "reverses:" the 1st array into 2nd */

char* reverse_them(char from[], char to[])
{
int i, asize, li;

asize = arr_size(from); /* get input array size */
li = asize - 1; /* because of last '\0' element */

for(i = 0; li >= 0; ++i)
to[li--] = from;

return to;
}



/* this function gets the size of an array */

int arr_size(char ar[])
{
int i;

for(i = 0; ar != '\0'; ++i)
;

return i;
}

----------------- OUTPUT ---------------------------
[arch@voodo kr2]$ gcc -std=c99 -Wall -Wextra 19-ex-1-19.c
[arch@voodo kr2]$ ./a.out
like

Richar Heathfield

array size: 25


dleifhtaeH rahciR

ekil
[arch@voodo kr2]$
 
S

santosh

arnuld said:
ok this is what, finally, i have got and it works

:-(

because i *cheat* by using /char*/ in creating the solution. at
chapter 1 i am not supposed to use /char*/.

You are not understanding the mechanics of arrays as function
arguments. When an array is used as a function argument, what is
actually passed to the function is simply a pointer to the first
element of the array. If you like, you can think of arrays as always
being passed to functions by reference, though, strictly speaking,
this is not correct. So your string reversing function actually gets
two pointer values to the start of the 'from' and 'to' arrays. It
manipulates these arrays, (whose scope is in the calling function),
*directly*, through these pointers, though you use array indexing
notation with the pointer objects rather than the more traditional
pointer notation.

So your first example did solve the problem fine without using pointer
explicit pointer notation, though pointers *cannot* be eliminated when
arrays are used in C. That's just the way C is built.

In your second attempt, you're unnecessarily returning a pointer to
the 'to' array. This is not necessary since both the arrays are local
to the calling function, (main.) It always has access to it.
can nybody do the same without using /pointers/ ?

/* 05.c - copy a string to an array in reversed order. */
#include <stdio.h>
#define MAXLINE 1024

unsigned long length(const char str[]) {
unsigned long int len = 0;

while (str[len] != '\0') len++;
return len;
}

void revstr(char to[], const char from[]) {
unsigned long int ctr, end = length(from);

for (ctr = 0; end != 0; end--, ctr++) to[ctr] = from[end - 1];
to[ctr] = '\0';
return;
}

int main(void) {
char line[MAXLINE], reversed[MAXLINE];
int c;
unsigned long int ctr = 0;

printf("Enter some text:\n");
while (ctr < (MAXLINE - 1) && (c = getchar()) != EOF && c != '\n')
line[ctr++] = c;
line[ctr] = '\0';
revstr(reversed, line);
printf("%s\n", reversed);
return 0;
}
 
A

arnuld

You are not understanding the mechanics of arrays as function
arguments. When an array is used as a function argument, what is
actually passed to the function is simply a pointer to the first
element of the array. If you like, you can think of arrays as always
being passed to functions by reference, though, strictly speaking,
this is not correct. So your string reversing function actually gets
two pointer values to the start of the 'from' and 'to' arrays. It
manipulates these arrays, (whose scope is in the calling function),
*directly*, through these pointers, though you use array indexing
notation with the pointer objects rather than the more traditional
pointer notation.

So your first example did solve the problem fine without using pointer
explicit pointer notation, though pointers *cannot* be eliminated when
arrays are used in C. That's just the way C is built.

In your second attempt, you're unnecessarily returning a pointer to
the 'to' array. This is not necessary since both the arrays are local
to the calling function, (main.) It always has access to it.
can nybody do the same without using /pointers/ ?

/* 05.c - copy a string to an array in reversed order. */
#include <stdio.h>
#define MAXLINE 1024

unsigned long length(const char str[]) {
unsigned long int len = 0;

while (str[len] != '\0') len++;
return len;

}

void revstr(char to[], const char from[]) {
unsigned long int ctr, end = length(from);

for (ctr = 0; end != 0; end--, ctr++) to[ctr] = from[end - 1];
to[ctr] = '\0';
return;

}

int main(void) {
char line[MAXLINE], reversed[MAXLINE];
int c;
unsigned long int ctr = 0;

printf("Enter some text:\n");
while (ctr < (MAXLINE - 1) && (c = getchar()) != EOF && c != '\n')
line[ctr++] = c;
line[ctr] = '\0';
revstr(reversed, line);
printf("%s\n", reversed);
return 0;

}

after understanding your programme, which was not fully clear to me. i
wrote my own without looking at anything and it runs BUT the same
problem, its OUTPUTs are wrong:

1) size is always "original size + 1"
2) it never prints the "reversed array"


it has been nearly 2 hours i am banging my head with this programme
and it still has "2 semantic errors" :-(


----------------- PROGRAMME -------------------
/* this programmes prints all the input in reverse order */


#include <stdio.h>

#define MAXLINES 1000

void reverse_str(char from[], char to[]);
int size_of_str(char arr[]);

int main(void)
{
int i, ichar;
char current_line[MAXLINES];
char reversed[MAXLINES];

i = 0;
while( ((ichar = getchar()) != EOF) && (i < MAXLINES - 1) )
current_line[i++] = ichar;;

current_line = '\0';

reverse_str(current_line, reversed);
printf("\nSize of input: %d\n", size_of_str(current_line));
printf("\n%s\n", reversed);

return 0;
}


void reverse_str(char from[], char to[])
{
int from_end;
int from_begin;

from_end = size_of_str(from) - 1;

for(from_begin = 0; from_end >= 0; ++from_begin)
to[from_begin] = from[from_end--];

to[from_begin] = '\0';
}

int size_of_str(char arr[])
{
int i = 0;

while(arr[i++] != '\0');

return i;
}

----------------- OUTPUT ------------------------
[arch@voodo kr2]$ gcc -std=c99 -Wall -Wextra testing.c
[arch@voodo kr2]$ ./a.out
like this

Size of input: 11


[arch@voodo kr2]$
 
S

santosh

arnuld said:
You are not understanding the mechanics of arrays as function
arguments. When an array is used as a function argument, what is
actually passed to the function is simply a pointer to the first
element of the array. If you like, you can think of arrays as always
being passed to functions by reference, though, strictly speaking,
this is not correct. So your string reversing function actually gets
two pointer values to the start of the 'from' and 'to' arrays. It
manipulates these arrays, (whose scope is in the calling function),
*directly*, through these pointers, though you use array indexing
notation with the pointer objects rather than the more traditional
pointer notation.

So your first example did solve the problem fine without using pointer
explicit pointer notation, though pointers *cannot* be eliminated when
arrays are used in C. That's just the way C is built.

In your second attempt, you're unnecessarily returning a pointer to
the 'to' array. This is not necessary since both the arrays are local
to the calling function, (main.) It always has access to it.
can nybody do the same without using /pointers/ ?

/* 05.c - copy a string to an array in reversed order. */
#include <stdio.h>
#define MAXLINE 1024

unsigned long length(const char str[]) {
unsigned long int len = 0;

while (str[len] != '\0') len++;
return len;

}

void revstr(char to[], const char from[]) {
unsigned long int ctr, end = length(from);

for (ctr = 0; end != 0; end--, ctr++) to[ctr] = from[end - 1];
to[ctr] = '\0';
return;

}

int main(void) {
char line[MAXLINE], reversed[MAXLINE];
int c;
unsigned long int ctr = 0;

printf("Enter some text:\n");
while (ctr < (MAXLINE - 1) && (c = getchar()) != EOF && c != '\n')
line[ctr++] = c;
line[ctr] = '\0';
revstr(reversed, line);
printf("%s\n", reversed);
return 0;

}

after understanding your programme, which was not fully clear to me. i
wrote my own without looking at anything and it runs BUT the same
problem, its OUTPUTs are wrong:

1) size is always "original size + 1"
2) it never prints the "reversed array"

it has been nearly 2 hours i am banging my head with this programme
and it still has "2 semantic errors" :-(

You might want to go back a few pages in K&R and start again. Your
main confusion is with C's semantics for arrays.
----------------- PROGRAMME -------------------
/* this programmes prints all the input in reverse order */

#include <stdio.h>

#define MAXLINES 1000

void reverse_str(char from[], char to[]);
int size_of_str(char arr[]);

int main(void)
{
int i, ichar;
char current_line[MAXLINES];
char reversed[MAXLINES];

i = 0;
while( ((ichar = getchar()) != EOF) && (i < MAXLINES - 1) )
current_line[i++] = ichar;;

current_line = '\0';

reverse_str(current_line, reversed);
printf("\nSize of input: %d\n", size_of_str(current_line));
printf("\n%s\n", reversed);

return 0;
}


void reverse_str(char from[], char to[])
{
int from_end;
int from_begin;

from_end = size_of_str(from) - 1;

for(from_begin = 0; from_end >= 0; ++from_begin)
to[from_begin] = from[from_end--];


Try:

to[from_begin] = from[--from_end];
to[from_begin] = '\0';
}

int size_of_str(char arr[])
{
int i = 0;

while(arr[i++] != '\0');

return i;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top