Please help me with my code. I am using the system() function in c. Let's say I want to make a new directory using C code.
char name[];
printf("Enter the name of directory: ");
scanf("%s", &name);
Then using system(), I want to use the variable name[]
instead of using or putting a fixed value like system("mkdir ryan"); which makes a new directory ryan; what I want to happen is that, to create any name of directory and store it to variable name[] and implement that value instead of ryan. Your answers are highly appreciated.
You should be using something like:
char name[100];
printf("Enter the name of the directory: ");
if (scanf("%99s", name) == 1) // Not &name
{
char command[120];
sprintf("%s %s", "mkdir", name);
if (system(command) != 0)
...oops...
}
First off (and this probably doesn't matter if your code is just an example), don't ever use an unbounded %s scanf - that opens you up to buffer overflows.
If you have a string like:
char name[] = "paxdiablo";
you can just use that to construct your own string for execution.
char cmd[1000];
strcpy (cmd, "mkdir ");
strcat (cmd, name);
system (cmd);
And make sure you know (or check with strlen, or dynamically allocate the buffer so it's big enough) the size of name so that you don't end up with a buffer overflow there as well.
An example of the dynamic allocation one:
void tryMkdir (char *dir) {
static char prefix[] = "mkdir ";
// Use sizeof to allow for null char at end.
char *cmd = malloc (sizeof (prefix) + strlen (dir));
if (cmd != NULL) {
strcpy (cmd, prefix);
strcat (cmd, dir);
system (cmd);
free (cmd);
}
}
(although you'd probably want some error checking in there in case the mkdir or malloc failed).
here is an example of how it could be implemented:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int main() {
char *dirname = NULL;
char *cmdline = NULL;
size_t len;
size_t dirlen = 0;
int rv = 0;
printf("Enter directory: ");
if ( (len = getline(&dirname, &dirlen, stdin)) < 0) {
perror("getline");
exit(-1);
}
dirname[len-1] = 0;
cmdline = malloc(len+8);
snprintf(cmdline, dirlen+8, "mkdir %s", dirname);
rv = system(cmdline);
free(cmdline);
free(dirname);
rv = WEXITSTATUS(rv);
return rv;
}
You'll need to build up a string w/ your full command to send to system() in it, which means allocating space for it (which you didn't do for name in your original code, so that your call to scanf would likely fail). For something like your mkdir example, you could create a string that starts with mkdir & has enough room after that for your directory name, and when you call scanf, point it to the location within that string you want the name to go; saves you having to do a strcat or somesuch afterward, and if this is the only thing you need the directory name for, why store it twice?
Try:
char command[80];
strcpy(command, "mkdir ");
strcat(command, name);
system(command);
Related
hey guys i have looked around for a solution and tried everything i can think of im new to pointers and dynamic strings and i could really do with some help with problem. im currently learning c and i need to get the user to input a dynamic size for the string length . i need to make it so the users input can not be bigger then 100 . here's where i am at currently . i have the code booting but if i try set the size to let's say 5 i can still input way more chars into the string. cheers really appreciate any help .
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
int maxSize = 100;
char *name = (char*) malloc (maxSize * sizeof (char));
int n;
char text1[]= ("input string size\n");
printf ("your string lenght is %d\n", strlen(name));
//getting size
n=intPrintScanner(text1);
printf ("your size is %d\n",n);
name = realloc (name, sizeof (char) * n);
//printing results
printf ("your string lenght is %d\n",strlen (name));
scanf("%s", name);
printf("your string is %s",name);
free(name);
fflush(stdin);
printf("press any key to close");
getchar();
return (0);
}
Bugs:
You never assign any data to name so it just contains garbage. You can't use strlen on it before you have stored valid data there either. You can store a string inside name by for example using strcpy.
When using realloc, there's no guarantee that the old pointer is the same as the returned pointer. Also, you need error handling. Implement it like this instead:
char* tmp = realloc (name, n);
if(tmp == NULL)
{
/* actual error handling here in case realloc fails */ }
}
name = tmp; // assign pointer to the new area only if allocation succeeded
fflush(stdin); is not well-defined, never use fflush on input streams. Instead you should discard unwanted line feed characters from stdin - which could be as trivial as an extra getchar() call just after reading something. Check out How to read / parse input in C? The FAQ for lots of general good advise regarding how to take input from stdin.
Cosmetic/style:
No need for parenthesis here: char text1[]= ("input string size\n");. All it achieves it to make the code look strange.
The correct form of main is int main (void). The int main() is obsolete style.
There is no need to wrap the expression passed to return in a parenthesis.
There is never a need to multiply something with sizeof (char), since sizeof (char) is by definition always 1 no matter system.
There is no need to cast the result of malloc.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
char* read_until(int fd, char end) {
int i = 0, size;
char c = '\0';
char* string = (char*)malloc(sizeof(char));
while (1) {
size = read(fd, &c, sizeof(char));
if (c != end && size > 0) {
string = (char*)realloc(string, sizeof(char) * (i + 2));
string[i++] = c;
} else {
break;
}
}
string[i] = '\0';
return string;
}
int main()
{
char *name;
int correct=0;
do{
write(1,"Put a name: ",strlen("Put a name: "));
name = read_until(STDIN_FILENO,'\n');
if(strlen(name) > 99){
write(1,"Error\n",strlen("Error\n"));
}else{
correct=1;
}
}while(correct != 1);
write(1,name,strlen(name));
free(name);
}
Try using write and read instead of printf and scanf, it is better for allocating dynamic memory, read and try to understand the read_until function, there are better ways to do main.
I am having an issue with the following code.
I have a global variable
char tokens[512][80];
Along with code:
int main(int argc, char** argv) {
char *input = malloc(sizeof(char) * 80);
while (1) {
printf("mini-shell>");
fgets(input, 80, stdin);
parse(input);
if (strcmp(tokens[0], "cd") == 0) {
cd();
}
else if (strcmp(tokens[0], "exit") == 0) {
exit(1);
}
}
}
void parse(char str[]) {
int index = 0;
char* str_ptr = strtok(str, " ");
while (str_ptr != NULL) {
strcpy(tokens[index], str_ptr);
str_ptr = strtok(NULL, " \0\r\n");
//printf("%d\n", index);
index = index + 1;
}
}
I found that if I enter exit for stdin I get a Segmentation fault, but if I enter cd .. for stdin I don't. Why is this so?
We don't know what the definition of the cd() function is, but there are a number of things that you may wish to consider in this program.
First, I don't believe there's any benefit to dynamically allocating 80 bytes of memory for the input buffer when you can easily do so automatically on the stack with char input[80]; - this is free and easy and requires no deallocation when you're done.
If you do this, you derive the size with fgets(input, sizeof input, stdin) where if you change the size of your input line from 80 to some other number, you only have to change it once: the sizeof on an array pulls the size directly.
Your parse() routine needs a little bit of help also. It's a really good idea to declare the function via the extern as shown so that when the compiler sees you call the function in the loop (right after the fgets), it knows the parameter and return types. Otherwise it has to make assumptions.
Because parse() is splitting apart the line you read from input, it's not required to copy the strings to some other place, so you can turn tokens from a multi-dimensional array into a simple array of pointers. As you run strtok() through the line to split up the parameters, you can store just the pointer, knowing that they will be pointing to stable data until the next fgets().
Also: your code does not strictly require or use this, but adding a NULL pointer to the end of the tokens list is a really good idea: otherwise, how does the caller know how many parameters were actually entered? This code checks whether the user entered just a blank line or not.
We've also change the loop around a little bit so the strtok() is called just once instead of twice, including the \n as noted in the comments.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *tokens[512];
extern void parse(char *str);
int main(int argc, char** argv) {
char input[80];
while (1) {
printf("mini-shell> "); fflush(stdout); // make sure user sees prompt
fgets(input, sizeof input, stdin);
parse(input);
if (tokens[0] == NULL) continue; // user entered blank line
if (strcmp(tokens[0], "cd") == 0) {
cd();
}
else if (strcmp(tokens[0], "exit") == 0) {
exit(1);
}
}
}
void parse(char *str) {
int index = 0;
char* str_ptr;
while ( (str_ptr = strtok(str, " \n")) != NULL)
{
tokens[index++] = str_ptr;
str = NULL; // for next strtok() loop
}
tokens[index] = NULL;
}
I am trying to read a file line by line and split it into words. Those words should be saved into an array. However, the program only gets the first line of the text file and when it tries to read the new line, the program crashes.
FILE *inputfile = fopen("file.txt", "r");
char buf [1024];
int i=0;
char fileName [25];
char words [100][100];
char *token;
while(fgets(buf,sizeof(buf),inputfile)!=NULL){
token = strtok(buf, " ");
strcpy(words[0], token);
printf("%s\n", words[0]);
while (token != NULL) {
token = strtok(NULL, " ");
strcpy(words[i],token);
printf("%s\n",words[i]);
i++;
}
}
After good answer from xing I decided to write my FULL simple program realizing your task and tell something about my solution. My program reads line-by-line a file, given as input argument and saves next lines into a buffer.
Code:
#include <assert.h>
#include <errno.h>
#define _WITH_GETLINE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define assert_msg(x) for ( ; !(x) ; assert(x) )
int
main(int argc, char **argv)
{
FILE *file;
char *buf, *token;
size_t length, read, size;
assert(argc == 2);
file = fopen(argv[1], "r");
assert_msg(file != NULL) {
fprintf(stderr, "Error ocurred: %s\n", strerror(errno));
}
token = NULL;
length = read = size = 0;
while ((read = getline(&token, &length, file)) != -1) {
token[read - 1] = ' ';
size += read;
buf = realloc(buf, size);
assert(buf != NULL);
(void)strncat(buf, token, read);
}
printf("%s\n", buf);
fclose(file);
free(buf);
free(token);
return (EXIT_SUCCESS);
}
For file file.txt:
that is a
text
which I
would like to
read
from file.
I got a result:
$ ./program file.txt
that is a text which I would like to read from file.
Few things which is worth to say about that solution:
Instead of fgets(3) I used getline(3) function because of easy way to knowledge about string length in line (read variable) and auto memory allocation for got string (token). It is important to remember to free(3) it. For Unix-like systems getline(3) is not provided by default in order to avoid compatibility problems. Therefore, #define _WITH_GETLINE macro is used before <stdio.h> header to make that function available.
buf contains only mandatory amount of space needed to save string. After reading one line from file buf is extended by the required amount of space by realloc(3). Is it a bit more "universal" solution. It is important to remember about freeing objects allocated on heap.
I also used strncat(3) which ensures that no more than read characters (length of token) would be save into buf. It is also not the best way of using strncat(3) because we also should testing a string truncation. But in general it is better than simple using of strcat(3) which is not recommended to use because enables malicious users to arbitrarily change a running program's functionality through a buffer overflow attack. strcat(3) and strncat(3) also adds terminating \0.
A getline(3) returns token with a new line character so I decided to replace it from new line to space (in context of creating sentences from words given in file). I also should eliminate last space but I do not wanted to complicate a source code.
From not mandatory things I also defined my own macro assert_msg(x) which is able to run assert(3) function and shows a text message with error. But it is only a feature but thanks to that we are able to see error message got during wrong attempts open a file.
The problem is getting the next token in the inner while loop and passing the result to strcpy without any check for a NULL result.
while(fgets(buf,sizeof(buf),inputfile)!=NULL){
token = strtok(buf, " ");
strcpy(words[0], token);
printf("%s\n", words[0]);
while (token != NULL) {//not at the end of the line. yet!
token = strtok(NULL, " ");//get next token. but token == NULL at end of line
//passing NULL to strcpy is a problem
strcpy(words[i],token);
printf("%s\n",words[i]);
i++;
}
}
By incorporating the check into the while condition, passing NULL as the second argument to strcpy is avoided.
while ( ( token = strtok ( NULL, " ")) != NULL) {//get next token != NULL
//if token == NULL the while block is not executed
strcpy(words[i],token);
printf("%s\n",words[i]);
i++;
}
Sanitize your loops, and don't repeat yourself:
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *inputfile = fopen("file.txt", "r");
char buf [1024];
int i=0;
char fileName [25];
char words [100][100];
char *token;
for(i=0; fgets(buf,sizeof(buf),inputfile); ) {
for(token = strtok(buf, " "); token != NULL; token = strtok(NULL, " ")){
strcpy(words[i++], token);
}
}
return 0;
}
So this course I'm doing wants us to play around with memory management and pointers. I'm not really fully understanding them.
I keep getting a error:
Segmentation fault (Core dumped)
Apparently I don't have access to memory?
It's something wrong in my slen function?
/*
In these exercises, you will need to write a series of C functions. Where possible, these functions should be reusable (not use global variables or fixed sized buffers) and robust (they should not behave badly under bad input eg empty, null pointers) .
As well as writing the functions themselves, you must write small programs to test those functions.
- Remember, in C, strings are sequences of characters stored in arrays AND the character sequence is delimited with '\0' (character value 0).
----------------------------------------------------
1) int slen(const char* str)
which returns the length of string str [slen must not call strlen - directly or indirectly]
*/
#include <stdio.h>
#include <stdlib.h>
/* Returns the length of a given string */
int slen(const char* str) {
int size = 0;
while(str[size] != '\0') {
size++;
}
return size;
}
/*
2) char* copystring(const char* str)
which returns a copy of the string str. [copystring must not call any variant of strcpy or strdup - directly or indirectly]*/
char* copystring(const char* str) {
int size = slen(str);
char *copy = (char*) malloc (sizeof(char) * (size + 1));
copy[size] = '\0';
printf("before loop");
int i = 0;
while (*str != '0') {
copy[i++] = *str++;
}
return copy;
}
int main() {
char *msg = NULL;
printf("Enter a string: ");
scanf("%s", &msg);
int size = slen(msg);
//printf("The length of this message is %d.", size);
// printf("Duplicate is %s.", copystring(msg));
// Reading from file
}
The problem isn't in your slen function, it happens before that when you're using scanf:
you need to make some space for the string that you're reading from the user using scanf
you don't need to pass the address of your memory buffer to scanf, the variable is already holding an address.
Amended code:
char msg[101];
printf("Enter a string: ");
scanf("%s", msg);
int size = slen(msg);
Alternately, if you're being asked to learn about memory allocation, study the usage of malloc:
char *msg = malloc(101);
printf("Enter a string: ");
scanf("%s", msg);
int size = slen(msg);
While learning about malloc, don't forget to also study up on the associated usage of free.
Also important and significant here is the management of your buffer size: when you make memory for the string that you'll be scanning from the user, you should put a limit on the amount of string that you actually read. There are a few ways to do this: start by studying the scanf format string, where you can use:
scanf("%100s", msg);
You need to assign memory to msg in your main
Either use char msg[10] or use malloc.
char *msg = malloc(10*sizeof(char))
Specifically, I am trying to build up the following statement and run it as the following command:
system("java -cp . mainpackage.SomeClass 1234567890 98765");
I have researched this online, but the examples did not compile, so I pieced together the following illustrative pseudo code. How do I change the code below to get it to concatenate the string and execute the command?
#include <stdio.h>
main() {
char jv[33];
strcpy(jv, "java -cp . mainpackage.SomeClass ");
char to[10];
strcpy(to, "1234567890 ");
char pin[5];
strcpy(pin, "98765");
system(jv + to + pin);
}
to and pin are arguments sent to a java program. Eventually, to and pin will be coming from inputs, but for now I just want to treat them as these values while I test other pieces of the code.
snprintf() is a flexible and a safe method. #fukanchik. The main challenge in C is to:
1) manage string memory space and
2) prevent overruns.
const char *jv = "java -cp . mainpackage.SomeClass ";
const char *to = "1234567890 ";
const char *pin = "98765";
#define BIGBUF 100
char command[BIGBUF];
snprintf(command, sizeof command, "%s%s%s", jv, to, pin);
system(command);
Or with C99 and assuming integers
const char *jv = "java -cp . mainpackage.SomeClass";
long to = 1234567890;
long pin = 98765;
int n = snprintf(NULL, 0, "%s %ld %ld", jv, to, pin);
char command[n+1];
snprintf(command, sizeof command, "%s %ld %ld", jv, to, pin);
system(command);
From an actual command line, like int main (int argc, char **argv)
char buf[1024] = {0};
int n;
for (n = 0; n < argc; n ++)
strcat (buf, argv[n]); // Change to strlcat if you have it available (BSD or Mac)
printf ("result = %s\n", buf);
Or using your example:
char jv[33];
strcpy(jv, "java -cp . mainpackage.SomeClass ");
char to[10];
strcpy(to, "1234567890 ");
char pin[5];
strcpy(pin, "98765");
system(jv + to + pin);
char result[1024] = {0}; // C does not zero format variables inside a function, so we do it ourselves with = {0}
sprintf (result, "%s %s %s", jv, to, pin); // Should use snprintf instead if available
printf ("result = %s\n", result);
OR
char result[1024] = {0};
strcat (result, jv);
strcat (result, " ");
strcat (result, to);
strcat (result, " ");
strcat (result, pin); // Should use strlcat instead if available
printf ("result = %s\n", result);
First, let me tell you the mistakes in above code.
char jv[33];
strcpy(jv, "java -cp . mainpackage.SomeClass ");
in C, strings are null-terminated, so you'll be needing an extra element per string to store the null. Expand the size of your array.
The, for concatenation like
system(jv + to + pin);
you can define an array large enough to hold the concatenated final value and use strcat() to concatenate the source and destination string. You can use a loop, to append more than one sub-string to make a complete command-string, as you want.