Forgotten code for user input in C in Linux Terminal - c

I've written the code, however I cannot remember how to get the user's input.
The command to run the code is ./rle "HHEELLLLO W" but in my code, I don't know how to get the code to read the "HHEELLLLO W".
If I have a regular printf function, the code will work and will print H1E1L3O 0W0 but I want it so any user's input can be calculated.
I tried using atoi but I think I've done it wrong and I don't know how to fix it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_RLEN 50
char* encode(char* src)
{
int rLen;
char count[MAX_RLEN];
int len = strlen(src);
char* dest = (char*)malloc(sizeof(char) * (len * 2 + 1));
int i, j = 0, k;
for (i = 0; i < len; i++) {
dest[j++] = src[i];
rLen = 1;
while (i + 1 < len && src[i] == src[i + 1]) {
rLen++;
i++;
}
sprintf(count, "%d", rLen);
for (k = 0; *(count + k); k++, j++) {
dest[j] = count[k];
}
}
dest[j] = '\0';
return dest;
}
int main(int argc, char ** argv)
{
char str[] = atoi(argv[1]);
char* res = encode(str);
printf("%s", res);
getchar();
}
When I compile it, I get this error:
rle.c: In function ‘main’:
rle.c:47:18: error: invalid initializer
char str[] = atoi(argv[1]);
^~~~
rle.c:45:14: error: unused parameter ‘argc’ [-Werror=unused-parameter]
int main(int argc, char ** argv)
^~~~
cc1: all warnings being treated as errors

atoi converts strings (of digits) to integers, which is nothing like what you to do here.
I would recommend doing this one of two ways:
(1) Use the command-line argument directly:
int main(int argc, char ** argv)
{
char* str = argv[1];
char* res = encode(str);
printf("%s\n", res);
}
This works because argv[1] is already a string, as you want. (In fact in this case you don't even need str; you could just do char* res = encode(argv[1]);.)
In this case you will have the issue that the shell will break the command line up into words as argv[1], argv[2], etc., so argv[1] will contain just the first word. You can either use quotes on the command line to force everything into argv[1], or use the next technique.
(2) Read a line from the user:
int main(int argc, char ** argv)
{
char str[100];
printf("type a string:\n");
fgets(str, sizeof(str), stdin);
char* res = encode(str);
printf("%s\n", res);
}
In both cases there's also some additional error checking you theoretically ought to do.
In the first case you're assuming the user actually gave you a command-line argument. If the user runs your program without providing an argument, argv[1] will be a null pointer, and your code will probably crash. To prevent that, you could add the test
if(argc <= 1) {
printf("You didn't type anything!\n");
exit(1);
}
At the same time you could double-check that there aren't any extra arguments:
if(argc > 2) {
printf("(warning: extra argument(s) ignored)\n");
}
In the second case, where you prompt the user, there's still the chance that they won't type anything, so you should check the return value from fgets:
if(fgets(str, sizeof(str), stdin) == NULL) {
printf("You didn't type anything!\n");
exit(1);
}
As you'll notice if you try this, there's also the issue that fgets leaves the \n in the buffer, which may not be what you want.

Related

generating main arguments without the parameter

In C programming language, is it possible to access int argc or char **argv without using the parameters? I know some of you might ask why this is needed, just for research purposes.
Is it possible to generate the cmd line arguments without using the main parameter variables ? For example, to illustrate some pseudo code, that i have in mind,
LPTSTR cmd = GetCommandLine();
splitted = cmd.split(" ") //split from spaces
char **someArgv.pushForEach Splitted, length++
and you'd have a someArgv with the parameters and length as argc, this'd really help to know if possible to illustrate.
If OP already has the command as a string, then:
Form a copy of the string
Parse it for argument count
Allocate for argv[]
Parse & tokenize copy for each argv[]
Call main()
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
// Not standard, but commonly available
char *strdup(const char *s);
// Return length of token and adjust offset to the next one
// Adjust as needed
// Presently only ' ' are used to separate
// More advanced would have escape characters, other white-space, etc.
size_t tokenize(const char *s, size_t *offset) {
// find following space
size_t len = strcspn(s + *offset, " ");
*offset += len;
// find first non-space
*offset += strspn(s + *offset, " ");
return len;
}
int call_main(const char *cmd) {
char *cmd2 = strdup(cmd);
cmd2 += strspn(cmd2, " "); // skip leading spaces
size_t offset = 0;
int argc = 0;
while (tokenize(cmd2, &offset) > 0) {
argc++;
}
char **argv = malloc(sizeof *argv * ((unsigned)argc + 1u));
offset = 0;
for (int a = 0; a < argc; a++) {
argv[a] = &cmd2[offset];
size_t len = tokenize(cmd2, &offset);
argv[a][len] = '\0';
}
argv[argc] = NULL;
int retval = 0;
#if 0
retval = main(argc, argv);
#else
printf("argc:%d argv:", argc);
for (int a = 0; a < argc; a++) {
printf("%p \"%s\", ", argv[a], argv[a]);
}
printf("%p\n", argv[argc]);
#endif
free(cmd2);
free(argv);
return retval;
}
Sample
int main() {
call_main(" name 123 abc 456 ");
}
argc:4 argv:0x800062322 "name", 0x800062327 "123", 0x80006232c "abc", 0x800062331 "456", 0x0
Pedantic: The strings provided to main() should be modifiable. Avoid code like
argv[1] = "Hello";
....
main(argc, argv);
#include <stdio.h>
int main(int argc, char *argv[]);
int callMain(void)
{
char *argv[4];
argv[0] = "binary";
argv[1] = "param1";
argv[2] = "param2";
argv[3] = NULL;
return main(3, argv);
}
int main(int argc, char *argv[])
{
if (argc <= 1)
{
return callMain();
}
printf("ARGC: %u\n", argc);
int i;
for (i = 0; i < argc; i++)
printf("ARG: %u - %s\n", i, argv[i]);
return 0;
}

Creating a format string with a variable number of specifiers

I am trying to use va_list & its associated macros with vsprintf() to create a format string that has a variable number of specifiers. Here is an example program I wrote in which the number of specifiers can only be altered via the NUM_ARG macro:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#define MAXBUF 4096
#define SPECIFIER "(%s)"
#define NUM_ARG 5
char *strmaker(int num_args, ...)
{
char form[MAXBUF] = { [0] = '\0' };
char *prnt = (char *) malloc(sizeof(char) * MAXBUF);
va_list strings;
for (int i = 0; i < num_args; ++i)
strcat(form, SPECIFIER);
va_start(strings, num_args);
vsprintf(prnt, form, strings);
va_end(strings);
return prnt;
}
int main(int argc, char *argv[])
{
if (argc != (NUM_ARG + 1))
return -1;
char *s = strmaker(NUM_ARG, argv[1], argv[2], argv[3], argv[4], argv[5]);
printf("%s\n", s);
free(s);
return 0;
}
However, this isn't exactly what I want to achieve. How could I do this with a variable number of arguments? How could a variable number of strings be passed to a function and used to initialise a va_list?
As far as I know, it is not possible to do that. If you are not so keen about using variadic functions and can redefine the function. The below code suits your need; Iterate through each item in the array and append to the string using snprintf.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXBUF 4096
#define SPECIFIER "(%s)"
char *strmaker(int num_args, char** strings)
{
char *prnt = (char *) malloc(sizeof(char) * MAXBUF);
int cur = 0;
/* Append the strings to the prnt buffer */
for (int i = 0; i < num_args; i++) {
int p_return = snprintf(prnt + cur, MAXBUF - cur, SPECIFIER, strings[i]); // If no error, return the number characters printed excluding nul (man page)
if (p_return >= MAXBUF - cur) // If buffer overflows (man page)
return prnt;
cur = cur + p_return; // Update the index location.
}
return prnt;
}
int main(int argc, char *argv[])
{
if (argc <= 1)
return -1;
char *s = strmaker(argc - 1, argv + 1);
printf("%s\n", s);
free(s);
return 0;
}
Terminal Session:
$ ./a.out 1 2 3
(1)(2)(3)
$ ./a.out 1 2 3 4 5 6 7
(1)(2)(3)(4)(5)(6)(7)
$ ./a.out Hello, This is stackoverflow, Bye
(Hello,)(This)(is)(stackoverflow,)(Bye)
Short answer is: You can't.
However you can work around it by using arrays of strings, possibly dynamically allocated. Then you could basically use the same technique you do now, but iterate over the array instead.
Perhaps something like this:
char *strmaker(size_t count, char *strings[])
{
// First get the length of all strings in the array
size_t result_length = 0;
for (size_t i = 0; i < count; ++i)
{
// +1 for space between the strings
// And for the last string adds space for the string null-terminator
result_length += strlen(strings[i]) + 1;
}
// Now allocate the string (using calloc to initialize memory to zero, same as the string null-terminator)
char *result = calloc(1, result_length);
// And not concatenate all strings in the array into one large string
for (size_t i = 0; i < count; ++i)
{
strcat(result, strings[i]);
if (i != count - 1)
{
strcat(result, " "); // Add space, except after last string
}
}
// Return the resulting string
return string;
}
int main(int argc, char *argv[])
{
// Create an array for all arguments
char **arguments = malloc(sizeof(char *) * argc - 1);
for (int a = 1; a < argc)
{
arguments[a - 1] = argv[a];
}
// Now create the single string
char *result = strmaker(argc - 1, arguments);
// ... and print it
printf("%s\n", result);
// Finally clean up after us
free(result);
free(arguments);
}
For the command-line arguments in argv you don't really need to create a new array to hold them, but it showcases how to create an array of string to pass to strmaker. You can use any strings you want instead of the command-line arguments.

Convert an array of command line arguments and store them in an int array

I am writing a program that takes an argument array from the command line(ex. 10 20 30 40), converts them into integers and saves them in an int array to be used later. I have declared a pointer for the heap. I want to store the number count from the CL in the length variable. Then allocate space for the length and copy it to the heap. Next, use a function that converts the command line arguments to an integer and copy them in a int array.I am confused as to how I can pass the command line values. Could someone point me in the right direction? Thanks.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void convert(char** source, int length);
int main(int argc, char *argv[]){
int length = 0;
char *p_heap;
if( argc > 11 || argc < 2 ) {
printf("arguments 1-10 are accepted %d provided\n", argc-1);
printf("Program Name Is: %s",argv[0]);
exit(EXIT_FAILURE);
}
length = argc-1;
p_heap = malloc(sizeof(length));
strcpy(p_heap, length);
convert(p_heap, length);
//printf("Average %f\n", avg());
puts(p_heap);
free(p_heap);
return 0;
}
void convert(char** source, int length){
int *dst;
int i;
for(i=0;i<length;i++) {
dst = atoi([i]);
}
}
Note: I am assuming correct input from CL.
I want to store the number count from the CL in the length variable.
If you assume correct input from CL, then you have this number in argc-1.
Then allocate space for the length and copy it to the heap.
dst = malloc((argc-1)*sizeof *dst);
Next, use a function that converts the command line arguments to an integer and copy them in a int array.
for(int i=0; i<argc-1; i++)
sscanf(source[i], "%d", &dst[i]);
You should also change the return type of convert to int * and then return dst.
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char **argv)
{
if (argc == 1)
return EXIT_SUCCESS;
long *data = malloc((argc - 1) * sizeof *data);
for (int i = 1; i < argc; ++i) {
char *endptr;
errno = 0;
data[i-1] = strtol(argv[i], &endptr, 10);
if (*endptr != '\0') {
fputs("Input error :(", stderr);
return EXIT_FAILURE;
}
if (errno == ERANGE) {
fputs("Parameter out of range :(\n\n", stderr);
return EXIT_FAILURE;
}
}
for (int i = 0; i < argc - 1; ++i)
printf("%ld\n", data[i]);
free(data);
}
why the comparison with 11 in if( argc > 11 || argc < 2 ) { ?
in
length = argc-1;
p_heap = malloc(sizeof(length));
sizeof(length) is sizeof(int) and does not depend on the value of length if it was your hope
In
strcpy(p_heap, length);
strcpy get two char*, length values the number of args rather than the address of an array of char, so the result is undefined and probably dramatic
In
convert(p_heap, length);
the first argument of convert must be a char** but p_heap is a char*
in
void convert(char** source, int length){
int *dst;
int i;
for(i=0;i<length;i++) {
dst = atoi([i]);
}
}
you do not use source
dst is a int* while atoi return an int
[i] ???
Before to give code on S.O. I encourage you to check first it compile without warning/error, using high warning level (e.g. gcc -pedantic -Wextra for gcc )

Taking input from command line as well as console(STDIN) in C

I am a beginner in coding and having difficulty trying to take input from both command line as well as console(STDIN). my program is supposed to search and replace a group of characters from a string. For example, concatenate cat gat : the output must be congatenate!
This is my code so far!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*Function to replace a string with another string*/
char *rep_str(const char *s, const char *old, const char *new1)
{
char *ret;
int i, count = 0;
int newlen = strlen(new1);
int oldlen = strlen(old);
for (i = 0; s[i] != '\0'; i++)
{
if (strstr(&s[i], old) == &s[i])
{
count++;
i += oldlen - 1;
}
}
ret = (char *)malloc(i + count * (newlen - oldlen));
if (ret == NULL)
exit(EXIT_FAILURE);
i = 0;
while (*s)
{
if (strstr(s, old) == s) //compare the substring with the newstring
{
strcpy(&ret[i], new1);
i += newlen; //adding newlength to the new string
s += oldlen;//adding the same old length the old string
}
else
ret[i++] = *s++;
}
ret[i] = '\0';
return ret;
}
int main(int argc, char*agrv[])
{
char mystr[100], c[10], d[10];
scanf("%s", mystr);
scanf(" %s",c);
scanf(" %s",d);
char *newstr = NULL;
newstr = rep_str(mystr, c,d);
printf("%s\n", newstr);
free(newstr);
return 0;
}
as for now, it shows correct output for either console input or commandline input, bur not both!
kindly suggest the changes to be made!
You can have a check on the variable argc of function int main().
// Path of executable file is passed by default so value of 'argc' will be at least 1
if(argc > 1)
{
// do stuff to work on input from command line
}else{
// do stuff to work on input from STDIN
}
Instead of trying to parse input file through argc and argv, simply pass all the input file through stdin. This means that you will always use scanf to read input data.
At command line you will need to call using pipes, something like this:
$ cat file.txt | yourprogram

Censor words in c

I've been working on a function which censors words. I've created this function and it works, except that it only accepts one argument. For example, when I do "./a.out test < example.txt", it replaces "test" with CENSORED in "example.txt". But when I add another one, like "./a.out test test2 < example.txt", it only replaces "test", not both "test" and "test2".
Can someone help me with my function please? I don't know what I'm doing wrong.
Here's the function:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
assert(argc > 1);
char fileRead[4096];
char replace[] = "CENSORED";
size_t word_len = strlen(argv[1]);
while (fgets(fileRead, sizeof(fileRead), stdin) != 0)
{
char *start = fileRead;
char *word_at;
while ((word_at = strstr(start, argv[1])) != 0)
{
printf("%.*s%s", (int)(word_at - start), start, replace);
start = word_at + word_len;
}
printf("%s", start);
}
printf("\n");
return (0);
}
I suggest you put in a middle loop over argv elements 1 to argc - 1. In each iteration, it would process the line to censor the corresponding argument, just as your function now does only for the first argument.
int arg;
for (arg = 1; arg < argc; arg += 1) {
/* ... censor argv[arg] ... */
}
Note that you can then drop the assert(), too, as structuring the argument access that way naturally avoids accessing the argv array outside its bounds (if no arguments are specified, the program will run without censoring anything).

Resources