Call by reference behavior when calling by value - c

I am working through chapter 1.9 of the K&R C book and I don't fully understand the example code given. In it, there is a function getline(line, MAXLINE) that returns an int of the length of a line.
However, right afterwards, the 'line' variable is used. From my understanding of functions, the line variable should not be modified and C is just passing line and MAXLINE to the function and the function returns the length of a line. This looks like a pass by reference function but the code is pass by value function.
Any help would be appreciated.
I stripped away most of the original code in the K&R book to try to better understand it but it is still confusing me.
#define MAXLINE 1000
int getLine(char, int);
int main(){
char line[MAXLINE];
int len;
printf("%s\n", line); //making sure that there is nothing in line
len = getline(line, MAXLINE);
printf("length: %d\n", len);
printf("%s", line); //now there's something in line!?
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;
}

int getline(char s[], int lim) is equivalent to int getline(char *s, int lim).
What that means is that s is a pointer, pointing to the location in memory where char line[MAXLINE] is stored, so by modifying the contents of s, you actually modify the line array declared in main.
Also you have a small bug in the code in the question. I believe that the forward declaration int getLine(char, int); should be int getline(char[], int); (note the [] and the lowercase l);

Related

Scope of variables in C, why is function modyfing values in main?

#include <stdio.h>
#define MAXLINE 100
int get_line(char line[], int maxline);
void copy(char to[], char from[]);
/*Prints longest input line*/
int main(){
int len; /*Current line length*/
int max; /*Maximum length so far*/
char line[MAXLINE]; /*Current input line*/
char longest[MAXLINE]; /*Longest line is saved here*/
max = 0;
while ((len = get_line(line, MAXLINE)) > 0){
if (len > max){
max = len;
copy (longest, line);
}
}
if (max > 0)
printf("%s", longest);
return 0;
}
/*get_line: read a line into s, return length*/
int get_line(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;
}
/*copy: Copy 'from' into 'to'*/
void copy (char to[], char from[]){
int i;
i = 0;
while((to[i] = from[i]) != '\0')
++i;
}
This code is from Section 1.9 of The C Programming Language, I'm trying to understand how it works. I'm not understanding how the scopes of the variables work. In the while loop the function get_line is modifying the variable line and the function copy is modifying the variable longest.
Shouldn't they be only in the scope of the function? I don't get why the functions is able to modify them in main
Array's names are actually a pointer to first element.
What [] operator does is same as *(array + n)
Edit: As pointed out in the comments, this might be confusing and misleading.
I recommend you taking a look at this question: Is an array name a pointer?
int a[10];
a[1] == *(a + 1) // true
get_line() and copy() has parameter type of char[], which is same as char*.
You passed memory address of line and longest to those functions.
Variables aren't completely inaccessible when out of scope,
you just can't reference them directly using names.
Normally function parameters are copy of original value passed to the function,
so changing them won't affect the original varaible.
But in this case you're passing memory address of a variable, and those functions are able to change value of array's elements through pointer.

Why does this program in Dennis Ritchie's "The C Programming Language" not work?

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.

Error in C program that I don't understand [duplicate]

This question already has an answer here:
Unable to compile sample code from The C Programming Language 2nd , page 29
(1 answer)
Closed 2 years ago.
I just started out learning C with "The C Programming Language" book. I have an experience in programming mainly in python so I'm not new and I usually understand errors and fix them, but this time I really don't understand what's wrong with the C program that I just copied from the book to get some practice.
#include <stdio.h>
#define MAXLINE 1000 /*Maximum input of the line size*/
int getline(char line[], int maxline);
void copy(char to[], char from[]);
/*Print longest input line*/
int main()
{
int len; //Current line size
int max; //The max lenght seen so far
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) //There was a line
printf("%s", longest);
return 0;
}
/* getline: read a line into s and return its lenght */
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;
}
/* copy: copy 'from' into 'to'; assume 'to' is big enough */
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
And here is the error message:
error: conflicting types for 'getline'
The problem is that getline() is (now) a standard POSIX library function (defined in <stdio.h>). Your function has the same name and is thus clashing with it.
The solution is to simply change the name.

An unexplained overflow in C

I'm writing code to find the longest row in the input stream and print it out. However, after I defined an int called max_count = 0, I always found an overflow, which displayed max_count as 1633771873. I've initialized that variable, so I don't know where the problem is. You probably do not need to figure out all of the functions, but each of them has its comment.
Here is my code:
#include <stdio.h>
#define DEFAULT 10
int getline(char line[], int limit);
void copy(char from[], char to[]);
int enlarge(int lim, char s[]);
main()
{
int i;
int max_count = 0;
char line[DEFAULT];
char maxline[DEFAULT];
while ((i = getline(line, DEFAULT)) != 0) {
if (i > max_count) { // where weird thing happend (max_count=1633771873)
max_count = i;
copy(line, maxline);
}
}
if (max_count > 0) {
printf("maxline: %s", maxline);
} else {
printf("No maxline");
}
return 0;
}
/*get a row from input stream and return its length*/
int getline(char s[], int lim)
{
int i, c;
for (i = 0; ((c = getchar()) != EOF) && (c != '\n'); ++i) {
if (i == lim - 1) {
lim = enlarge(lim, s);
}
s[i] = c;
}
if (c == '\n') {
s[i] = c;
++i;
}
if (i == lim) {
enlarge(lim, s);
}
s[i] = '\0';
return i;
}
/*copy an array to another */
void copy(char from[], char to[])
{
int i = 0;
while (from[i] != '\0') {
to[i] = from[i];
++i;
}
}
/*expand an array twice as its capacity*/
int enlarge(int lim, char s[])
{
s[lim - 1] = '\0';
lim *= 2;
char temp[lim];
copy(s, temp);
s = temp;
return lim;
}
This is the console window:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
^Z
maxline:
--------------------------------
Process exited after 15.19 seconds with return value 3221225477
You have a buffer with space for 10 characters:
#define DEFAULT 10
char line[DEFAULT];
You enter 37 characters including a newline:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Your getline function tries to store them all in line (by the way, enlarge doesn't do anything useful).
The first 10 characters fit into line. The other 27 characters and the terminating '\0' overwrite other random variables which come after line in memory.
That is why max_count holds the ASCII codes for aaaa.
Your enlarge function isn't doing what you think it is.
int enlarge(int lim, char s[])
{
s[lim - 1] = '\0';
lim *= 2;
char temp[lim];
copy(s, temp);
s = temp;
return lim;
}
You're creating a new array temp within the scope of the function. You then copy the address of the start of the array to s. Since s is a parameter to the function, modifying s won't be reflected in the calling function. So after this function returns s in getline is unchanged.
Even if you were to fix this by either returning a char * or changing the function to accept a char ** and assigning temp to the dereferenced pointer, you would be returning the address of a variable local to enlarge. That variable goes out of scope when the function returns and so the pointer would be invalid.
The only way you can change the size of an array is if you first allocate it dynamically with malloc and then later use realloc to change its size.
Also, getline is the name of a function on POSIX systems. You should change the name to something else.

Can someone interpret the for loop for me?

#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.

Resources