#include <stdio.h>
#define MAXLINE 10
void reverse(char s[]);
void getline(char b[], int lim);
int main() {
char s[MAXLINE];
getline(s, MAXLINE);
reverse(s);
return 0;
}
void reverse(char s[]) {
int i;
int len = 0;
for (i=0; s[i] != '\0'; i++) {
len = len + 1;
}
char b[len + 1];
for (i = 0; i < len; i++) {
b[(len - 1) - i] = s[i];
b[len] = '\0';
}
printf("%s : %s\n", s, b);
}
void getline(char b[], int lim) {
char c;
int i;
for (i=0; i < lim-1 && (c = getchar())!= EOF && (c!='\n'); ++i) {
b[i] = c;
}
if (c == '\n') {
b[i] = '\n';
}
}
why am i getting an error for the get line unction? It says in Xcode "conflicting types for 'get line'. Also in another error, it says "Too few arguments to function call, expected 3, have 2?
Also can someone explain the order of evaluation for the "condition" part of the for loop? (I'm talking about the &&'s). Thanks a lot!!!
(1)..Your program is correct.But,already one library function getline is exist in library.We know that predefined function's prototype declarations are present in header file.For getline predefined function, declaration is already present in stdio.h...In your program, you are also declared prototype for getline .We know well that It is not possible two declarations for one function.So only you got error.Try to run your program with othername for that function...
(2)..for (i=0; i < lim-1 && (c = getchar())!= EOF && (c!='\n'); ++i)
In for loop you are checking three conditions..you are checking for '\n' also.so,You should give input as string format only.But actually it is not string.You should give characters as input continuously without pressing ENTER.
Related
I am studying "The C Programming Language, 2nd Ed." by Brian Kernighan and Dennis Ritchie. I was on Exercise 1-19 of the book. The question asks to define a function reverse(s) which reverses a character string a. And we have to write a program which reverses it's input one at a time.
//This program is working on online compiler but not here
#include <stdio.h>
void reverse(char s[]);
int main(void) {
int h = 0; // sort of automatic variable just to
// keep storing characters in current line
char s[200];
char c;
for (int i = 0; i < 1000; i++)
s[i] = '\0';
while ((c = getchar()) != EOF) {
if (c != '\n') {
s[h++] = c;
} else {
s[h++] = c;
h = 0;
reverse(s);
for (int i = 0; i < 1000; i++)
s[i] = '\0';
}
}
}
void reverse(char s[]) {
int i = 200;
while(i >= 0)
if(s[i--] != '\0')
putchar(s[i]);
printf("\n");
}
So when I run this code with gcc on my system, I don't get any errors while compiling, but I can't type any input for some reason. However, the program runs correctly when I use an online C compiler.
void reverse(char s[]) {
int i = 200;
while(i >= 0)
if(s[i--] != '\0')
putchar(s[i]);
printf("\n");
}
if you postdecrement your string index, you are first using value at 200 position, which is invalid (it's one position out of the array) so you are doing bad. To do it properly, you need to predecrement it, as in:
void reverse(char s[]) {
int i = 200;
while(i >= 0)
if(s[--i] != '\0')
putchar(s[i]);
printf("\n");
}
but there's still an error... as you pass a null terminated string, you cannot be sure of what there is in the array after the null.... (can be another null?) so you have to search for the null from the beginning of the string (and this is good, because the most of the time you will feed the routine short strings, and now you don't depend on the array size, which you assumed by a constant 200. One good way to do it is with the strlen() function, as in:
void reverse(char s[]) {
int i = strlen(s);
while(i >= 0) /* ??? see below */
if(s[--i] != '\0')
putchar(s[i]);
printf("\n");
}
and then, the test you do is not necessary at all (you already found the leftmost null):
void reverse(char s[]) {
int i = strlen(s);
while(i >= 0) /* still more below VVV */
putchar(s[--i]);
printf("\n");
}
... and there's still a little mistake... you have to stop when i <= 0 and not when i < 0 as you are predecrementing now:
void reverse(char s[]) {
int i = strlen(s);
while(i > 0) /* here!! */
putchar(s[--i]);
printf("\n");
}
I'm starting to learn C and came across the following program in Dennis Ritchie's The C Programming Language (2nd edition):
#include <stdio.h>
#define MAXLINE 1000
int getline(char line[], int maxline);
void copy(char to[], char from[]);
int main()
{
int len;
int max;
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */
max = 0;
while ((len = getline(line, MAXLINE)) > 0)
{
if (len > max)
{
max = len;
copy(longest, line);
}
}
if (max > 0)
printf("%s", longest);
return 0;
}
int getline(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;
}
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
When I run this program exactly as is, it does not compile because there are conflicting definitions of getline. It turns out there is a getline in stdio.h, and that's where the conflict comes from. I assume this is non-standard or was added to the library after the book was published. In any case, that error was easily fixed by simply changing the name of the function to getLine.
After making that change, the program compiles but never actually completes. What I did notice is that getLine adds both a newline character and a null terminator (\0) to the character array s, and the value it returns, while it is meant to be the length of the character array, is actually that length + 1. Modifying the function to return i - 1 instead of i fixes the issue.
My question is: why does it fix the issue? I doubt that it's a typo, but maybe that's possible? Or could it be a compiler issue? Do some compilers count a null terminator as a character (i.e. to be included in the length of the character array) while others don't?
I should also say that I'm using an M1 MacBook, so I guess it's possible that the code translates to different machine code which creates different results?
EDIT:
The following is the modified code that works for me:
#include <stdio.h>
#define MAXLINE 1000
int getLine(char line[], int maxline);
void copy(char to[], char from[]);
int main()
{
int len;
int max;
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */
max = 0;
while ((len = getLine(line, MAXLINE)) > 0)
{
if (len > max)
{
max = len;
copy(longest, line);
}
}
if (max > 0)
printf("%s", longest);
return 0;
}
int getLine(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 - 1;
}
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
Also, when I say that the original code never completes, I mean that I can type anything, press enter, type some more, press enter, etc. then finally just press enter without typing (the code is checking for an array of length zero, so this is where it should print out the line of max length and exit), and the program continues running.
When I run this program exactly as is, it does not compile because there are conflicting definitions of getline
There is a getline function offered as an extension in some implementations, and its prototype is conflicting with the example in the book. That's most likely what's happening with you. Awesome as K&R is, it's an old book at this point and out of date in many respects.
The easiest way to get around this is to rename your getline function to getLine or get_line or something else. Alternately you'll need to undefine _GNU_SOURCE or _POSIX_C_SOURCE before including stdio.h, either in your code or on the command line.
I'm writing code to reverse the char array in every single line I input. However, when I debugged the program, I encountered a segmentation fault and I don't know why.
Here is my code:
#include <stdio.h>
#define DEFAULT 1000
int reverse(char s[]);
main()
{
int i;
char line[DEFAULT] = {'\0'};
while ((i = getline(line, DEFAULT)) != 0) {
printf("%s", reverse(line));
}
return 0;
}
/*reverse a line*/
int reverse(char s[])
{
int i = 0, j = 0;
while (s[i] != '\n')
++i;
for (j = 0; j < i; ++j) {
s[2 * i - j] = s[j];
}
for (j = 0; j < i; ++j) {
s[j] = s[j + i + 1];
s[j + i + 1] = '\0';
}
return i;
}
/*get a line from input stream*/
int getline(char s[], int lim)
{
int i, c, j = 0;
for (i = 0; ((c = getchar()) != EOF) && (c != '\n'); ++i) {
if (i < lim - 2) {
s[j] = c; // use j to prevent index out of bounds
++j;
}
}
if (c == '\n') {
s[j] = c;
++j;
}
s[j] = '\0';
return i; // return the length of char s[]
}
When I input "abc\n" and execute reverse(s), the content in s becomes "cba\n" and i refers to 3, everything is okay. The segmentation fault happens when I step out of that function.
Here are some more details:
Complier: GCC 4.9.2 64-bit Release
System: Windows 10
Your function int reverse(char s[]) is returning an int, and then you're trying to print that resulting int as a string:
printf("%s", reverse(line));
If you want to use the function like that, you could change its signature to return a char* instead:
char* reverse(char s[]);
And then return the s that you're giving in as a parameter. Your compiler should issue a warning about giving the wrong type of parameter to printf. If not, try to set it to be more strict with warnings.
I'm going through the book "The C Programming Language" and doing all of the examples plus poking around in GDB to see what's going on.
In the below example code, the goal is to evaluate a few lines of text to determine which is the longest line. I thought my own program was failing because gdb was hanging at the for loop which calls getchar(). I followed the backtrace, found the culprit function, but couldn't determine the exact problem. Then I did the same with the example code, and the exact same problem occurs at the for loop which calls getchar().
// file: ch1/ex16.c
// OBJECTIVE: Revise the main routine o the lnogest program
// so it will correctly print the length of arbitrarily long
// lines and as much as possible of the text.
#include <stdio.h>
#define MAXLINE 1000
int getLine(char line[], int maxline);
void copy(char to[], char from[]);
int main()
{
int len, max;
char line[MAXLINE], longest [MAXLINE];
max = 0;
while ((len = getLine(line, MAXLINE)) > 0) {
if (len > max) {
max = len;
copy(longest, line);
}
}
if (max > 0) {
printf("%s", longest);
}
return 0;
}
int getLine(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;
}
void copy(char to[], char from[])
{
int i = 0;
while ((to[i] = from[i]) != '\0'){
++i;
}
}
Unlike when executing the program through the shell, gdb wouldn't accept ^d (ctrl+d) as EOF. Thanks to the comment that Duck provided above, I found that if I fed it a file through standard input gdb it solved the problem.
Ex:
(gdb) run < file.txt
I'm trying to reverse a string in C. The reverse function simply assigns the character at a given location (in a for loop) to a temp object. I cannot see any logic errors within the program, and the program compile successfully under gcc 4.7.2 with this command:
gcc -Wall -std=c99 reverse.c
To recreate the problem:
1.) Run the program and enter a string into your shell
2.) Once finished inputting, press enter/and or your EOF signal.
The problem is that neither the original string is printed, or the reversed string. This is also an exercise from K&R second edition, if you have completed this exercise, a different solution to mine would be appreciated.
I think the bug is caused by the absence of a null character, the famous printf requires a null terminated string to print input to cin. The getline function assigns a null character to the end of the array, surely the null character will be the first character in the string thereto ending the printf (and thus no character/literal is printed).
#include <stdio.h>
#define MAXLINE 1000
int geline(char s[], int lim);
void reverse(char line[], int length);
int main()
{
char s[MAXLINE];
char t[MAXLINE];
int k, len;
while ((len = getline(s, MAXLINE)) > 0) {
if (len > 1)
reverse(s, len);
}
printf("%s", s);
return 0;
}
void reverse (char input[], int length)
{
char temp[MAXLINE];
int j = length;
for (int i = 0; i < length; ++i, --j) {
temp[i] = input[i];
input[i] = input[j];
input[j] = temp;
}
}
int getline(char s[], int lim)
{
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;
}
There are two logic errors:
int j = length; should be int j = length - 1;
temp[i] = input[i] ... input[j] = temp;
There are two approaches for that last error:
Define temp as a single char: char temp; ... temp = input[i]; input[i] = input[j]; input[j] = temp;
Use the correct index in temp: temp[i] = input[i]; input[i] = input[j]; input[j] = temp[i]
Try this code:
#include <stdio.h>
#define MAXLINE 1000
int geline(char s[], int lim);
void reverse(char line[], int length);
int main () {
char s[MAXLINE];
char t[MAXLINE];
int k, len;
while ((len = getline(s, MAXLINE)) > 0) {
if (len > 1)
reverse(s, len);
}
printf("%s", s);
return 0;
}
void reverse (char input[], int length) {
char temp;
int j = length - 1;
for (int i = 0; i < j; ++i, --j) {
temp = input[i];
input[i] = input[j];
input[j] = temp;
}
}
int getline (char s[], int lim) {
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;
}
(I did my compiling with -Wall -std=c99 -O3 -g, the -g to allow use of gdb)
Here are the things I noticed and some ways of addressing them. I've tried to hew pretty closely to the style you started with (I would have converted the array decls in the prototypes to pointers, for example, but that's not necessary).
Your getline prototype was missing the t.
int getline(char s[], int lim);
In main, you don't actually need k, t[MAXLINE], and your printf should probably be in the loop so you'll see each word as it's reversed. Note that printf picks up a \n, since the getline below converts both newline and EOF-terminated lines to the same thing (without newlines):
int main()
{
char s[MAXLINE];
int len;
while ((len = getline(s, MAXLINE)) > 0) {
if (len > 0)
reverse(s, len);
printf("%s\n", s);
}
return 0;
}
In above, the getline(s, MAXLINE) could have been getline(s, sizeof(s) / sizeof(*s) - 1) although again, be careful of fencepost errors (note the - 1).
The reverse function can be greatly improved without going over to the madness of xor to skip having a variable (although Daffra's example is interesting, especially in that it correctly stops in the middle). Instead, having the sense to just index up to the halfway point is a clear win. Between that and dropping reducing the temp array to just a temporary character, your general style is retained.
void reverse (char input[], int length)
{
int max = length - 1; /* keep the final NUL in place */
for (int i = 0; i <= max / 2; ++i) {
char ch = input[i];
input[i] = input[max - i];
input[max - i] = ch;
}
}
In the above gcc -O3 can do a serious workover on the code, so there's no real reason to worry that long division is going to be performed on every loop test, etc. For example, gdb reports that i itself gets optimized out automatically, which is pretty interesting. Write good, readable code first, have some faith in your compiler, optimize later.
And last, getline benefits from testing against lim (CRITICAL!) and and converting newlines into NULs.
int getline(char s[], int lim)
{
int i, c;
for (i=0; (i <= lim) && ((c=getchar()) != EOF) && (c != '\n'); ++i)
s[i] = c;
s[i] = '\0';
return i; /* return the index to the final NUL, same as length w/o it */
}
Setting MAXLINE to 10 temporarily shows that this version handles overlong lines fairly gracefully, splitting them into two separate ones without losing any of the characters.
Be careful with strings to very clearly decide whether you want to describe them in terms of length, or in terms of the index to the NUL at the end. This affects how you phrase your loops, limits, variable names, etc, and obviously confusing them is a classic source of fencepost errors.
Hope this helps.
int j = length - 1; // Thanks to #chux
for (int i = 0; i < j; ++i, --j) { // or <= length / 2
char temp = input[i];
input[i] = input[j];
input[j] = temp;
temp is not needed, and not entirely correctly used.
You are twice swapping the values, which restores the swap on the second half of the cycling. :)
Your prototype misses a 't' (geline). Hence maybe
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
is taken?
you can use this fast function :
inline char * reverse(char *p)
{
char *save=p;
char *q = p;
while(q && *q) ++q;
for(--q; p < q; ++p, --q)
*p = *p ^ *q,
*q = *p ^ *q,
*p = *p ^ *q;
return save ;
}
Please have a look at this code:
#include <stdio.h>
#define MAXLINE 1000
int geline(char s[], int lim);
void reverse(char line[], int length);
int main()
{
char s[MAXLINE];
int len;
while ((len = geline(s, MAXLINE)) > 1) {
if (len > 1) {
reverse(s, len);
printf("%s", s);
}
}
return 0;
}
void reverse (char input[], int length)
{
char temp;
int j = length-1;
for (int i = 0; i < j; ++i, --j) {
temp = input[i];
input[i] = input[j];
input[j] = temp;
}
}
int geline(char s[], int lim)
{
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;
}
Only 2 changes needed here, and it will do the reverse fine.
Inside function reverse just do this
int j = --length;
Instead of this:
input[j] = temp; //you should use
input[j] = temp[i];