I have been trying to get strcmp to return true in the following program for many days now, I have read the man pages for strcmp, read, write... I have other's posts who have had the exact same problem. The following source code is just a test program that is frustrating the heck out of me, there are some commented out lines that are other attempts I've made at getting strcmp to work as expected. I have compiled with 'gdb -g' and stepped through one instruction at a time. The printf statements pretty much tell the whole story. I cannot get the value of buf, or bufptr to equal 't' ever. I have simplified the program, and had it just print one character at a time one after the other to the screen and they print as expected from whatever file is read-in, however, as soon as I start playing with strcmp, things get crazy. I cannot for the life of me figure out a way to get the value in buf to be the single char that I am expecting it to be.
When simplified to just the write(1,...) call, it writes the expected single char to stdout, but strcmp to a single 't' never returns 0. !!!!! Thank you in advance. I originally didnt have bufptr in there and was doing a strcmp to buf itself and also tried using bufptr[0] = buf[0] and the still were not the same.
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define BUF_SIZE 1
void main(int argc, char *argv[])
{
char buf[BUF_SIZE];
int inputFd = open(argv[1], O_RDONLY);
char tee[] = "t";
int fff = 999;
char bufptr[BUF_SIZE];
// char *bufptr[BUF_SIZE];
while (read(inputFd, buf, BUF_SIZE) > 0) {
bufptr[0] = buf[0];
// bufptr = buf;
printf("********STRCMP RETURNED->%d\n", fff); // for debugging purposes
printf("--------tee is -> %s\n", tee); // for debugging purposes
printf("++++++++buf is -> %s\n", buf); // " " "
printf("########bufptr is -> %s", bufptr); // " " "
write (1, buf, BUF_SIZE);
if ((fff = strcmp(tee, bufptr)) == 0)
printf("THIS CHARACTER IS A T");
}
close(inputFd);
}
The str-family of functions expects strings as inputs, which are arrays storing null-terminated character sequences. However, you do not provide space in the buffer for the null character. To make the buffers strings, you need to add space for the null-character and zero-out the value so that they end with the null character.
void main(int argc, char *argv[])
{
char buf[ BUF_SIZE + 1 ] = {0};
int inputFd = open(argv[1], O_RDONLY);
char tee[] = "t";
while (read(inputFd, buf, BUF_SIZE) > 0) {
if ( strcmp( tee, buf ) == 0 )
printf("THIS CHARACTER IS A T");
}
close(inputFd);
}
Related
I'm using a Ubuntu Machine compiling with Clang.
I'm reading a simple file, storing it into a buffer then getting the length. I'm anticipating receiving a 5 but got a 6.
strlen() isn't suppose to include the null terminator. Is this perhaps because I performed a cast on the buffer?
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
unsigned char buffer[30];
memset(buffer, '\0', 30);
int fd_read = open("test.txt", O_RDONLY);
read(fd_read, buffer, 29);
ssize_t length = strlen((const char *)buffer);
printf("%zu\n", length);
}
Contents of test.txt:
Hello
Output:
6
strlen() isn't suppose to include the null terminator.
That is true.
Is this perhaps because I performed a cast on the buffer?
The cast is unnecessary but it is not what is causing the problem.
I'm reading a simple file, storing it into a buffer then getting the length. I'm anticipating receiving a 5 but got a 6.
The likely scenario is that you have newline character at the end of the read string, as pointed out by Chris Dodd, which strlen will count. To remove it:
buffer[strcspn(buffer, "\n")] = '\0';
Other considerations about your code:
You should verify the return value of open to confirm that the file was successfuly accessed.
memset(buffer, '\0', 30); is unnecessary, you can null terminate buffer:
ssize_t nbytes = read(fd_read, buffer, sizeof buffer - 1);
if(nbytes >= 0)
buffer[nbytes] = '\0';
Or you can initialize the array with 0s:
unsigned char buffer[30] = {'\0'}; // or 0
Your program is somewhat convoluted, using modified types for no reason. Yet the problem does not come from these typing issues nor the use of casts, it is much more likely the file contains 6 bytes instead 5, namely the letters Hello and a newline(*).
Here is a modified version:
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main() {
char buffer[30] = { 0 };
int fd_read = open("test.txt", O_RDONLY);
if (fd_read >= 0) {
int count = read(fd_read, buffer, sizeof(buffer) - 1);
size_t length = strlen(buffer);
printf("count=%d, length=%zu\n", count, length);
printf("contents: {");
for (size_t i = 0; i < count; i++) {
printf("%3.2X", (unsigned char)buffer[i]);
}
printf(" }\n");
close(fd_read);
}
return 0;
}
(*)or possibly on legacy platforms, Hello and an end of line sequence CR/LF (7 bytes) that is translated to a single '\n' byte by the read library function that is a wrapper on system calls that performs complex postprocessing
I made following program that uses read (system call in C) to get a string from user (of length lesser than 100).
#include<stdio.h>
#include <unistd.h>
#include <string.h>
int main() {
char *s;
int a = read(0, s, 100);
s[a-1] = '\0';
printf("\"%s\" \n read returned: %i; NUL at: %u", s, a, strlen(s));
return 0;
}
What I expected here is, it will get characters until user enters a new-line character. It will then replace that '\n' character by '\0', and print it.
The program works well until I enter 15 or less characters in stdin, but stops working when there are more than 16 characters.
My inputs are as follows:
E:\My Files\Codes>a.exe
1234567890123456
"1234567890123456"
returned = 17; length = 16
E:\My Files\Codes>a.exe
12345678901234567
[My program hanged on this input.]
Why does it only hangs on 16? What is special in this 2^2?
Post script: I used the string.h just to get the length of the string. Once my program starts working good, I will remove it.
I have been testing your code. The faults is: You have a pointer which points nowhere. I solve it reserving and allocating memory for your string (char array). I will post the working code:
#include <stdlib.h> // It is needed for malloc, free, etc...
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main() {
char *s = malloc(100*sizeof(char)); // Allocate memory with malloc
int a = read(0, s, 100);
s[a-1] = '\0';
printf("\"%s\" \n read returned: %i; NUL at: %u", s, a, strlen(s));
free(s); // You need liberate memory before exit
return 0;
}
Also, other way to solve this, without dynamic memory is:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main() {
char s[100]; // s is a char array of 100 elements
int a = read(0, s, 100);
s[a-1] = '\0';
printf("\"%s\" \n read returned: %i; NUL at: %u", s, a, strlen(s));
return 0;
}
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
char buf[10];
int ret;
while(1) {
ret = read(0, buf, sizeof buf);
printf("%s\n", buf);
}
return(0);
}
Basically, this is what happens:
$ gcc -Wall above.c
$ ./a.out
h
h
#
a
a
&
^C
$
How do I make it so that this special character is not printed? I'm unsure how to fix this. I tried making buf[10] = '\0' but I still get the same error.
You have several errors, why don't use the return value of read?
Simply you can use it in a "%.*s" format specifier, like in
printf("%.*s\n", ret, buf);
but....
you have to check that ret < 0 for errors.
you have to check that ret == 0 for End of file condition.
read(2) never terminates the sequence of characters read with a \0 char, so you cannot use any str* function on it (I used the trick of printing only the first ret chars because the ret variable tells me there are not more, so I don't get behind the last character read) but this approach will eat all the characters read after an actual \0 in the input file (or in the buffer), up to the ret-esim char. That is because the %*s format stops before the specified ret value if it finds the string terminator null char.
It is better to use write(2) or fwrite(2) with read(2), as in:
write(1, buffer, ret);
As read(2), write(2) doesn't treat \0 as a string terminator, and case you have some \0 chars in the buffer, it will print them, as if they were normal characters. This is important if you do want verbatim output from input (as in cat(1) command)
read() does not zero terminate anything. It is a function that is used to read any bytes from a file descriptor, including zero bytes. As such, zero terminating the result would be kind of pointless. Instead, read() returns the amount of bytes that were successfully read. You must interpret that return value if you want to do correct reading.
You have to initialize the 'buf' with null. As 'buf' is declares local array and you didn't initialize it with null, 'read' call is reading up to sizeof(buf) which is 10 bytes. If you giving input string less than sizeof(buf) size, then it will read the remaining junk characters from the 'buf'. So initialize the 'buf' with null.
int main(int argc, char **argv) {
char buf[10] = {'\0'};
int ret;
while(1) {
ret = read(0, buf, sizeof buf);
printf("\n%s\n", buf);
}
return(0);
}
buf[10] = ... is undefined behavior. The buffer goes from 0..9, so the naive approach should be buf[9] = 0;.
This still doesn't work because it is not linked to how much you actually read. You do know this because of the ret variable - so add buf[ret] = 0; before trying to output buf.
edit: as pointed out in the comments, if the full amount of chars has been read (in this case 10) then buf[ret] is the same as buf[10] and so it is still undefined behavior. Easiest solution is to ensure the buffer is bigger than the max size you are trying to read.
you should set buf[ret] to '\0' not buf[10].
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
char buf[10];
int ret;
while(1) {
ret = read(0, buf, sizeof(buf));
buf[ret] = '\0';
printf("%s\n", buf);
}
return(0);
}
well, as commented there are some mistakes in my answer. I just want to point out the single point, so I haven't consider too much.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv) {
char buf[10];
int ret;
while(1) {
ret = read(0, buf, sizeof(buf) - 1); // keep last byte for termination charactor
if (ret == -1) {
printf("error:%s\n", strerror(errno));
break;
} else if (ret == 0) {
// end of file. such as ctrl + D
break;
} else {
// ret certainly less than sizeof(buf)
buf[ret] = '\0';
printf("%s\n", buf);
}
}
return(0);
}
I'm trying to write a program that takes any number of one-word text string arguments, each less than 128 characters long. The program copies text from stdin to stdout, except that any of the words seen in the input are replaced with the word "CENSORED".
Example:
I have this file called poem.txt:
Said Hamlet to Ophelia,
I'll draw a sketch of thee,
What kind of pencil shall I use?
2B or not 2B?
The program should do this:
./censor Ophelia < poem.txt
Said Hamlet to CENSORED,
I'll draw a sketch of thee,
What kind of pencil shall I use?
2B or not 2B?
Here's my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char lines[200][200];
int numLines=0,i,j;
int nbytes = 128;
int bytes_read=0;
char *my_string;
char * pch;
//reading from stdin
while(stdin)
{
my_string=(char *) malloc (nbytes + 1);
bytes_read = getline (&my_string, &nbytes, stdin);
strcpy(lines[numLines++],my_string);
}
//scanning and replacing specified words by "CENSORED"
for(i=0;i<argc;i++)
{
for(j=0;j<numLines;j++)
{
pch = strstr (lines[j],argv[i]);
strncpy (pch,"CENSORED",8);
}
}
//display the result in output screen
for(j=0;j<numLines;j++)
{
printf("\n%s",lines[i]);
}
}
The problem is that this is giving segmentation fault, but I can't identify the mistake.
You're not properly overwritting a hit with the replacement which might be longer or shorter -- you're just stuffing it in regardless (potentially overwriting the terminal \0, possibly leading to your segmentation fault). Also, it looks like you miss double hits as you only check each command line word once against each line. Finally, you've made this more complicated by storing all the lines -- no line affects any other so why store them rather than process and print each line in turn?
Here's a overall simplified approach with more detailed replacement code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define REPLACEMENT "CENSORED"
#define BUFFER_SIZE (1024)
int main(int argc, char *argv[])
{
ssize_t bytes_read;
char *s, *line = malloc(BUFFER_SIZE);
size_t nbytes = BUFFER_SIZE, replacement_length = strlen(REPLACEMENT);
// read from stdin
while ((bytes_read = getline(&line, &nbytes, stdin)) != -1)
{
// scanning and replacing specified words
for (int i = 1; i < argc; i++)
{
while ((s = strstr(line, argv[i])) != NULL)
{
size_t search_length = strlen(argv[i]);
size_t tail_length = strlen(s + search_length);
(void) memmove(s + replacement_length, s + search_length, tail_length + 1);
(void) memcpy(s, REPLACEMENT, replacement_length);
}
}
// display the result in output screen
(void) fputs(line, stdout);
}
free(line);
}
Oh yeah, and you forgot to free what you malloc'd. And you're searching for the name of the program as one of your targets...
EXAMPLE
> ./a.out pencil 2B < poem.txt
Said Hamlet to Ophelia,
I'll draw a sketch of thee,
What kind of CENSORED shall I use?
CENSORED or not CENSORED?
I want to use read() and write() methods for reading from and writing to console instead of the original scanf() and printf(), as the first ones has system calls support using signals.
I have to make a mini Unix shell, which forks into children when performing a command. Here is my initial try for testing the reading and writing:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define COMMAND_LENGTH 1024
#define NUM_TOKENS (COMMAND_LENGTH / 2 + 1)
void read_command(char *buff, char *tokens[], _Bool *in_background) {
// to be implemented later
}
void createStr(char **str) {
if (*str != NULL) {
free(*str);
*str = NULL;
}
*str = (char*)malloc(sizeof(char) * COMMAND_LENGTH);
}
void delStr(char** str) {
if (*str != NULL) {
free(*str);
*str = NULL;
}
}
int main(int argc, char *argv[]) {
char input_buffer[COMMAND_LENGTH];
char *tokens[NUM_TOKENS];
char *inp = NULL;
while (true) {
write(STDOUT_FILENO, "> ", strlen("> "));
createStr(&inp);
read(STDIN_FILENO, input_buffer, sizeof(char) * COMMAND_LENGTH);
strcpy(inp, input_buffer);
write(STDOUT_FILENO, inp, strlen(inp));
_Bool in_background = false;
read_command(inp, tokens, &in_background);
}
delStr(&inp);
return 0;
}
My output for sample inputs are not the desired ones. Here is a sample output:
> Peterson
Peterson
��> Makr
Makr
son
��> Mark
Mark
son
��> Jon
Jon
son
��>
I don't know what is going on. Like why the special characters are showing up, as well as having parts of my last input in my new input. I need help in this.
You must store the return value of read, verify that read completed and null terminate the string before passing it to strcpy. read can indeed be interrupted by a signal and must be restarted in this case. read can also return a partial line, you should keep reading and concatenating into the command buffer, carefully reallocating the buffer if needed, until you receive either an end of file of the character '\n'.