Getting exact user input, c - c

I've been looking for a solution to this and haven't found any, I've been trying to make a string that is the size that the user inputs, is there any way to go about doing this? (I'm trying to eliminate null values in the char array).
Edit: I apologize about the missing info, the compiler is gcc -std=c99, and the OS is Ubuntu.
here is the part of the main program that I'm focusing on + the headers (not entirely completed), I'm trying to create a string that is the same length as the user inputs, and that contains the same values.
The compiler currently doesn't recognize myalloc and getline
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
char *string;
int selection, bytes_read, nbytes = 255;
unsigned char key, letter;
do {
...
printf("Enter a sentence:\n");
string = (char *) myalloc(nbytes + 1);
bytes_read = getline(&string, &nbytes, stdin);
...
}while(..);
}

Save the following as main.c:
#define _POSIX_C_SOURCE 200809L
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
int
main()
{
size_t n = 0;
char * line = NULL;
ssize_t count;
printf("Enter a sentence: ");
count = getline(&line, &n, stdin);
if (count < 0)
{
perror("getline");
return EXIT_FAILURE;
}
/* If it bothers you: get rid of the terminating '\n', if any. */
if (line[count - 1] == '\n')
line[count - 1] = '\0';
printf("Your input was: '%s'\n", line);
free(line);
return EXIT_SUCCESS;
}
Then, in a terminal:
$ gcc -o main main.c
$ ./main
Enter a sentence: the banana is yellow
Your input was: 'the banana is yellow'
There is also a more extensive example of using getline included in its man page.

Related

If i input too many characters my program either has a 'mremap_chunk(): invalid pointer' or a 'realloc(): invalid old size'

my program was built as a test to input as many sentences as the user want (until he enters -1), and then concatenate all sentences (\n included). If i input some characters is fine, but if i input more then 25 characters i have the two errors listed above, i tried simulating what would happen in paper and i canĀ“t find the problem, help is appreciated, thanks in advance.
The code is displayed below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char *s = malloc(1), *sentence = malloc(0);
int sSize = 0;
printf("Insert sentences, press '-1' if you want to exit:\n");
do
{
fgets(s,100,stdin);
if(strcmp(s,"-1\n") != 0)
{
sSize += strlen(s);
sentence = realloc(sentence, sSize * sizeof(char));
//s[strcspn(s, "\0")] = '\n';
strcat(sentence, s);
}
}while(strcmp(s,"-1\n") != 0);
printf("==================sentence================\n");
printf("%s", sentence);
return 0;
}
This is a classic buffer overrun problem:
s = malloc(1) - s now points to a one-character buffer.
fgets(s,100,stdin); - reads up to 100 characters into s - which is a one-character buffer.
EDIT
Here's a version which works and doesn't use a separate "sentence buffer":
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
const char *terminator = "-1\n";
char *sentences = malloc(100);
char *pNext_sentence;
printf("Insert sentences, press '-1' if you want to exit:\n");
*sentences = '\0';
do
{
sentences = realloc(sentences, strlen(sentences)+100);
pNext_sentence = sentences + strlen(sentences);
fgets(pNext_sentence, 100, stdin);
} while(strcmp(pNext_sentence, terminator) != 0);
*(sentences + (strlen(sentences) < strlen(terminator) ? 0 : strlen(sentences) - strlen(terminator))) = '\0';
printf("==================sentences================\n");
printf("%s", sentences);
free(sentences);
return 0;
}
You must use reallocate memory with realloc before using fgets, which, in your case, reads 100 bytes.
Your string has the initial size of 1.

Why is this code giving segmentation fault?

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?

Reversing a string in C using Visual Studio

I'm building a program for reversing a string in visual studio, and while I run the code and enter a word I want to reverse, the program crashes.
#include <stdio.h>
#include <conio.h>
#include <string.h>
main(void) {
char r[256];
int i, d;
printf("\nEnter the word you want to reverse : ");
gets_s(" %s", r, sizeof(r));
d = strlen(r);
for (i=d;i!=0;i--) {
printf("%s",i);
}
return 0;
}
Please note that I tried your program on Linux, so no MS Visual C++ and more specifically no conio.h and gets_s.
There are multiple problems with your program:
Your call to gets_s is incorrect, according to this and this, gets_s is defined as:
char *gets_s(
char *buffer,
size_t sizeInCharacters
);
You are calling it with illegal arguments. Instead of gets_s(" %s", r, sizeof(r)); you need to call it like this:
gets_s(r, 256);
the first parameter is pointer to the string buffer where the gets_s function will store the line from input and the second is the size of the buffer, note that in char r[256] you can store 255 characters and terminating zero (\0).
Your for loop is incorrect instead of for (i=d;i!=0;i--) { you need to do it like this:
for (i=d-1;i>=0;i--) {
now the loop starts from last character instead of \0 and ends when the i < 0 ie. the last print will be when i=0.
And your final mistake is that you are using printf incorrectly instead of printf("%s",i); you need to do:
printf("%c",r[i]);
because you are printing characters: "%c" is for char output and r[i] is i-th character from string r (don't forget that we count from 0).
So, in total this is how the program should look like:
#include <stdio.h>
#include <conio.h> // does not exist on GCC (Linux)
#include <string.h>
main(void) {
char r[256]; // 255 characters + \0
int i, d;
printf("\nEnter the word you want to reverse : ");
gets_s(r, 256); // store at most 255 characters + \0
// does not work on GCC (Linux) even with -std=C11
d = strlen(r);
// start from last character and include first
for (i=d-1;i>=0;i--) {
// %c - character, r[i] gets the i-th character from string r
printf("%c",r[i]);
}
return 0;
}
void rev(char *s)
{
char *start, *end;
end = start + strlen(s) - 1;
for (start = s; end > start; ++start, --end) {
char tmp;
tmp = *start;
*start = *end;
*end = tmp;
}
}
Use the fgets function, and also put the reversing code in its own function, like I did. So the final code is
int main()
{
char line[80];
fgets(line, 80, stdin);
/* don't allow empty string */
if (*line == '\0') {
fprintf(stderr, "Empty string is not a string\n");
return 1;
}
/* remove the \n placed by fgets */
remnl(line);
rev(line);
printf("%s\n", line);
return 0;
}
void remnl(char *s) { s[strlen(s) - 1] = 0; }
#include <stdio.h>
#include <string.h>
#include <conio.h>
int main(void) {
char r[256];
int i, d;
printf("\nEnter the word you want to reverse : ");
gets_s(r, sizeof(r));
d = strlen(r) - 1;
for (i = d; i >= 0; i--) {
printf("%c", r[i]);
}
_getch();
return 0;
}

How to chdir using C in Linux environment

I am new in c programming. How can I change directory like /home/jobs/$ans/xxx/ while I have $ans is a user string I can't chdir in c program.
My script is below:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char jdir;
printf("Enter job directory:"); /* user input for different directories */
scanf("jdir");
chdir("/home/jobs/%jdir/xxx");
system("ls -ltr");
return(0);
}
How to change directory with chdir?
Use something like:
char jdir[200]
scanf("%s", &jdir);
char blah[200];
snprintf(blah, 199, "/home/jobs/%s/xxx", jdir);
chdir(blah);
It seems mildly silly to write this program in C, but if there is a good reason to do so (for instance if it has to be setuid) then you should be a great deal more defensive about it. I would do something like this:
#define _XOPEN_SOURCE 700 /* getline */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
char *jobdir = 0;
size_t asize = 0;
ssize_t len;
fputs("Enter job directory: ", stdout);
fflush(stdout);
len = getline(&jobdir, &asize, stdin);
if (len < 0) {
perror("getline");
return 1;
}
jobdir[--len] = '\0'; /* remove trailing \n */
if (len == 0 || !strcmp(jobdir, ".") || !strcmp(jobdir, "..")
|| strchr(jobdir, '/')) {
fputs("job directory name may not be empty, \".\", or \"..\", "
"nor contain a '/'\n", stderr);
return 1;
}
if (chdir("/home/jobs") || chdir(jobdir) || chdir("xxx")) {
perror(jobdir);
return 1;
}
execlp("ls", "ls", "-ltr", (char *)0);
perror("exec");
return 1;
}
The edit history of this answer will demonstrate just how hard it is to get this 100% right - I keep coming back to it and realizing that I forgot yet another case that needs to be defended against.

C cannot open text file

I tried to make a program that tells you how many words, lines and characters are in a text file, but the function fopen() fails to open the file. I tried both absolute and relative paths to the text file but I get the same output. Can you please tell me what's wrong?
My compiler is gcc version 4.6.3 (Linux)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 256
void tokenize(const char *filename)
{
FILE *f=NULL;
char line[N],*p;
unsigned long int ch=0,wd=0,ln=0;
int t;
f=fopen(filename,"rt");
if(f==NULL)
{
perror("The following error occurred");
exit(1);
}
fgets(line,N,f);
while(!feof(f))
{
ln++;
p=strtok(line," ");
while(p!=NULL)
{
wd++;
t=strlen(p);
ch+=t;
printf("Word number %lu with length %d: %s\n",wd,t,p);
p=strtok(NULL," ");
}
fgets(line,N,f);
}
printf("%lu lines, %lu words, %lu characters\n",ln,wd,ch);
fclose(f);
}
int main(void)
{
char filename[80];
size_t slen;
printf("Enter filename path:\n");
fgets(filename,80,stdin);
slen = strlen (filename);
if ((slen > 0) && (filename[slen-1] == '\n'))
filename[slen-1] = '\0';
printf("You have entered the following path: %s\n",filename);
tokenize(filename);
return 0;
}
output:
Enter filename path:
input.txt
You have entered the following path: input.txt
The following error occurred: No such file or directory
You've retained the newline character from the input in your filename. You can see this when you echo the filename in your output: notice the blank line.
You'll need to strip off this newline before you pass it to your function. There are a few ways to do this, here's one:
size_t idx = strlen(filename);
if ((idx > 0) && filename[idx - 1] == '\n')
filename[idx - 1] = '\0';
You need to remove the trailing newline character from your string, with something like:
size_t slen = strlen (filename);
if ((slen > 0) && (filename[slen-1] == '\n'))
filename[slen-1] = '\0';
And, while I applaud your use of fgets for user input (since it can be protected from buffer overflow), there's still a couple of edge cases you haven't considered, such as when the line is too long, or the user flags end of input). See here for a more robust solution.
You can declare a function like:
void rmnewline(char *s)
{
int l=strlen(s);
if(l>0 && s[l-1]=='\n')
s[l-1]='\0';
}
and call it before using your char array.

Resources