jakub1998
jakub1998

Reputation: 400

Scanning char array using read()

Can I set char array by using read method in a function? I tried the way below, but it didn't give any effect. For me I take a pointer in method() argument, I save the data to it by read() and then I just "give" address of args to text. Don't blame me, I used to code in java, so the pointers may be used wrong, pay attention to every mistake I made (and inform me, please).

void method(char* text) {
 char args[100];
 int read = read(STDIN_FILENO, args, 100); // i write "sth" on keyboard
 text = args;
}

in main:

char c[100];
method(c);
printf("%s",c); // should print "sth"

Upvotes: 0

Views: 148

Answers (1)

ShadowRanger
ShadowRanger

Reputation: 155418

Simplest solution: Make method require (by documentation guarantees, since C can't force a specific array size to be passed) the caller to provide the size 100 buffer, rather than maintain a local and non-local buffer. You'll also want to return the result from read, so the caller knows how many valid bytes they received:

/* ...
 * text - must point to at least 100 bytes of valid memory
 * Returns number of read bytes
 */
int method(char* text) {
    return read(STDIN_FILENO, text, 100); // i write "sth" on keyboard
}

and in main:

char c[100];
// Store number of valid bytes available
int numvalid = method(c);
// Use .* to specify a dynamic maximum field width, so you don't have a read overflow
printf("%.*s", numvalid, c); // should print "sth"

Other approaches include having the function perform the allocation for the caller (with the caller passing a double-pointer and freeing the buffer themselves):

int method(char** text) { // Receives double-pointer so it can change caller's char*
    *text = malloc(100); // Dynamic allocation (add error checking)
    return read(STDIN_FILENO, *text, 100); // i write "sth" on keyboard
}

char *c = NULL; // Pointer to be filled, not array
int numvalid = method(&c); // Pass address of pointer so method can change c
// Use .* to specify a dynamic maximum field width, so you don't have a read overflow
printf("%.*s", numvalid, c); // should print "sth"
free(c); // Free memory allocated by method

Or keep using your current, separated buffers, and copy from one to the other before the method exits via memcpy (which copies the data), not via pointer assignment (which doesn't change anything visible to the caller):

int method(char* text) {
    char args[100];
    int read = read(STDIN_FILENO, args, 100); // i write "sth" on keyboard
    // Copy data from args to text buffer
    // Note: Using memcpy, *not* strcpy, because read provides no guarantees
    // that the buffer will be NUL-terminated
    memcpy(text, args, read);
    return read; // Still need to return number of valid bytes
}

char c[100];
int numvalid = method(c);
printf("%.*s", numvalid, c); // should print "sth"

This approach is kind of pointless though; method still requires a 100 byte buffer to be passed to operate safely, it just needlessly puts the data in a temporary space, then copies it to the final destination to waste cycles.

Finally, a solution that remains safe, while not requiring you to add a return value to method:

/* ...
 * text - must point to at least 100 bytes of valid memory
 * On return, data is NUL-terminated, *unless* 100 non-NUL bytes were read
 */
void method(char* text) {
    int numread = read(STDIN_FILENO, text, 100);
    if (0 <= numread && numread < 100) text[numread] = '\0';

    // Or the one-liner for people who don't believe in error handling: :-)
    // text[read(STDIN_FILENO, text, 100)] = '\0';
}

and then the caller can assume that their buffer is at most 100 bytes, so they can use a limiter on the %s format code to stop on NUL or after 100 bytes, whichever comes first:

char c[100];
method(c);
// Use .100 to prevent read overflow, knowing that method NUL terminated
// anything shorter than 100 bytes (preventing undefined behavior reading
// uninitialized bytes for smaller reads)
printf("%.100s", c); // should print "sth"

Upvotes: 1

Related Questions