I am making my own version of make. I allow for some arguments to be passed via command line.
I am working on it in chunks. I am setting the fileName right now
I have the following code
int main(int argc, char *argv[]) {
char *fileName = NULL;
char fileFlag[2];
strcpy(fileFlag, "-f");
printf("%s\n", fileFlag);
if (argc == 1) {
fileName = (char *) malloc(sizeof("Makefile"));
strcpy(fileName, "Makefile");
printf("One arg %s\n", fileName);
}
printf("\n%s", fileName);
return 0;
}
When it runs I get the following output.
-f
One arg Makefile
Shouldn't it print another line?
The first problem is
strcpy(fileFlag, "-f");
fileFlag is one element short of the required space, you need to have 3 element-array to store "-f" along with the terminating null. In this case, as per the strcpy() behaviour,
The strcpy function copies the string pointed to by s2 (including the terminating null
character) into the array pointed to by s1. [...]
So, including the null-character, the size of the source is 3, so is needed for the destination also. Otherwise, you'll be accessing out of bound memory which invokes undefined behavior.
That said,
please see this discussion on why not to cast the return value of malloc() and family in C..
Always check for the success of malloc() before using the returned pointer.
Related
I need to read a filename from a text file.
Then I have to use it as an argument for fopen .
Consequently , I need to read it as a const char* because this is the type fopen accepts as a first argument. How do I do this?
I tried something like:
FILE *a;
a=fopen("a.txt","r");
const char *filename
fgets(filename,100,a);
image=fopen(filename,"rb");
Something is be wrong as I receive a segmentation fault when I do this. I think that the variable filename is not well-received by the fopen function.
You may have seen that fopen() takes an argument of type (const char *), but you need to be able to modify your string before you pass it to the function. Also, you need to allocate space for your string, and you might consider allocating space for more than 100 chars. The stdio.h header file contains the macro FILENAME_MAX, which expands to an integer constant of the correct size for an array that will hold the longest possible file name string on a system. For example, you can use char filename[FILENAME_MAX];. When the identifier filename is encountered in the call to fopen(), it decays to a pointer to char, which is converted to a pointer to const char, as per the function prototype.
Furthermore, fgets() keeps the newline when if fetches a line of text, so you will need to remove that. You should check the result of fgets(), as it returns a NULL pointer in the event of an error or if it is called at end-of-file; otherwise it returns a pointer to the first char in filename[].
FILE *a;
a=fopen("a.txt","r");
char filename[FILENAME_MAX];
char *ch;
ch = fgets(filename,FILENAME_MAX,a);
/* Remove trailing newline */
if (ch) {
while (*ch != '\0' && *ch != '\n') {
++ch;
}
if (*ch == '\n') { // replace '\n' with '\0'
*ch = '\0';
}
image=fopen(filename,"rb");
}
First, your seg fault likely comes from trying to use memory that you do not own. i.e. by creating the variable:
const char *filename;
And not giving it any memory ([c][m]alloc) before trying to use it.
Regarding your statement:
Consequently , i need to read it as a const char*.
Not necessarily.
The first argument of the fopen prototype: "FILE *fopen(const char *filename, const char *mode)" simply guarantees that the argument passed in that position will be treated as a const char * within the fopen function.
The argument can be passed using a simple char *, eg. either of these forms:
char *filename = {"somefilename.txt"};
or
char filename[80];
strcpy(filename, "somefilename.txt");
And, as mentioned in comments, and other answers, remove the newline character, \n before passing as an argument.
EDIT Thanks Joachim. Used the function signature as you pointed out, and passed the address of my strings in. Inside the function, I did the realloc() using *currBuffer, and placed the values into the string using (*currBuffer)[lenBuffer] .... :)
Passing the value of the pointer by-value was working fine until realloc() decided it needed to assign a different memory space. I must have only checked the pointer's address on entry to the function and not noticed that it changed later.
.........................................................
My program gets user input from stdin, and then parses it into tokens.
As I read each character entered, I make a call addChrToLine(userInput, charCount-1, (char) inputChr); to void addChrToLine (char *currBuffer, int lenBuffer, char inputChr) where I add the new character to the string.
Later, when I'm parsing the input, I using the same addChrToLine function while I build the parsed string. However, when the parser calls the function, it gives an error on the 25th character.
My code to read user input:
char * userInput = malloc(sizeof(char));
int charCount = 0;
LOOP
if (!(inputChr == LF)) { // ignore the LF character as it denotes end of input line
charCount++;
addChrToLine(userInput, charCount-1, (char) inputChr);
continue;
}
My code to add the char to the current line:
void addChrToLine (char *currBuffer, int lenBuffer, char inputChr) {
currBuffer = realloc(currBuffer, sizeof(char) * (lenBuffer +2));
if (currBuffer == NULL) {
perror(NULL);
exit(ENOMEM);
}
currBuffer[lenBuffer] = (char) inputChr;
currBuffer[lenBuffer+1] = (char) '\0';
}
My code where I parse the input:
char * parsedCmd = malloc(sizeof(char));
int ndxOutput = 0;
Switch statement inside a loop to handle variety of cases
char currChr = command[ndxInput];
if (addChr) {
ndxOutput++;
addChrToLine2(parsedCmd,ndxOutput-1,currChr);
// parsedCmd = realloc(parsedCmd, sizeof(char) * (ndxOutput+2));
// parsedCmd[ndxOutput] = command[ndxInput];
// parsedCmd[ndxOutput+1] = '\0';
addChr = FALSE;
}
For input = alphabet, eg "abcde...yz", the user input string is read correctly and everything is as expected on entry to the parsing stage.
While parsing "a" to "w", the char * pointer parsedCmd correctly shows the contents. When I pass "x" to addChrToLine, it correctly places the character and adjusts the position of the null. BUT on return to the parser's next line, parsedCmd shows a null string.
The memory location of the pointer is the same during addChrToLine and after the call as it was before (so realloc() hasn't moved my data). However, when I look at the memory, the first 8 characters of the string are now 0x00 and the the string is intact inclusively after "i", all the way to "w" (no "x").
When the code tries to add "y" to parsedCmd, the realloc() statement issues an error double free or corruption (fasttop): 0x0000000000605160 ***
I'm a bit puzzled why this is happening.
And what puzzles me even more is that if I comment out the call to addChrToLine and uncomment the next three lines (which do the same thing), there is no error and the parser finishes fine.
Clearly I'm doing something wrong with my pointers or memory allocations, but I can't see what's wrong.
Can someone please help me understand what's going on here?
The error is that C passes arguments by value, meaning they are copied. So when you assign to currBuffer in the function you only assign (and modify) the local copy. When the function returns, the old userInput is still unchanged.
To fix this you have to pass the pointer by reference which is done with pointers in C, that is you have to pass a pointer to the pointer:
void addChrToLine (char **currBuffer, int lenBuffer, char inputChr);
...
addChrToLine(&userInput, charCount-1, (char) inputChr);
Another solution is to return the new pointer:
char *addChrToLine (char *currBuffer, int lenBuffer, char inputChr)
{
...
return currBuffer;
}
...
userInput = addChrToLine(userInput, charCount-1, (char) inputChr);
I'm trying to get input from the user while allocating it dynamically and then "split" it using strtok.
Main Questions:
Im getting an infinite loop of "a{\300_\377" and ",".
Why do i get a warning of "Implicitly declaring library function "malloc"/"realoc" with type void"
Other less important questions:
3.i want to break, if the input includes "-1", how do i check it? As you can see it breaks now if its 1.
4.In the getsWordsArray() i want to return a pointer to an array of strings. Since i dont know how many strings there are do i also need to dynamically allocate it like in the getInput(). (I dont know how many chars are there in each string)
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
char getInput()
{
char *data,*temp;
data=malloc(sizeof(char));
char c; /* c is the current character */
int i; /* i is the counter */
printf ("\n Enter chars and to finish push new line:\n");
for (i=0;;i++) {
c=getchar(); /* put input character into c */
if (c== '1') // need to find a way to change it to -1
break;
data[i]=c; /* put the character into the data array */
temp=realloc(data,(i+1)*sizeof(char)); /* give the pointer some memory */
if ( temp != NULL ) {
data=temp;
} else {
free(data);
printf("Error allocating memory!\n");
return 0 ;
}
}
printf("list is: %s\n",data); // for checking
return *data;
}
void getWordsArray(char *input)
{
char *token;
char *search = " ,";
token = strtok (input,search);
while (token != NULL ) {
printf("%s\n",token);
token = strtok(NULL,search);
}
}
EDIT:
i noticed i forgot to "strtok" command so i changed it to token = strtok(NULL,search);
I still get wierd output on the printf:
\327{\300_\377
Change:
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
to:
int main(int argc, const char * argv[])
{
char *input = getInput();
getWordsArray(input);
}
with a similar to the return value of getInput():
char *getInput()
{
// ...
return data;
}
In your code, you were only saving the first character of the input string, and then passing mostly garbage to getWordsArray().
For your malloc() question, man malloc starts with:
SYNOPSIS
#include <stdlib.h>
For your getchar() question, perhaps see I'm trying to understand getchar() != EOF, etc.
Joseph answered Q1.
Q2: malloc and realoc returns type void *. You need to explicitly convert that to char *. Try this:
data = (char *) malloc(sizeof(char));
Q3: 1 can be interpreted as one character. -1, while converting to characters, is equivalent to string "-1" which has character '-' and '1'. In order to check against -1, you need to use strcmp or strncmp to compare against the string "-1".
Q4: If you are going to return a different copy, yes, dynamically allocate memory is a good idea. Alternatively, you can put all pointers to each token into a data structure like a linked list for future reference. This way, you avoid making copies and just allow access to each token in the string.
Things that are wrong:
Strings in C are null-terminated. The %s argument to printf means "just keep printing characters until you hit a '\0'". Since you don't null-terminate data before printing it, printf is running off the end of data and just printing your heap (which happens to not contain any null bytes to stop it).
What headers did you #include? Missing <stdlib.h> is the most obvious reason for an implicit declaration of malloc.
getInput returns the first char of data by value. This is not what you want. (getWordsArray will never work. Also see 1.)
Suggestions:
Here's one idea for breaking on -1: if ((c == '1') && (data[i-1] == '-'))
To get an array of the strings you would indeed need a dynamic array of char *. You could either malloc a new string to copy each token that strtok returns, or just save each token directly as a pointer into input.
Assume I have char **argv. How do I determine its size?
I have a string - an example would be: sleep 30 & that is held in argv. I would like to be able to access the last array in *argv. In this case, the last array contains &. How can I access it? strlen(argv) doesn't seem to work properly. sizeof() obviously wouldn't work properly because **argv is a pointer.
Note: I am not talking about **argv as an argument in main(), therefore, I do not have argc or any other indicator of how long the string is.
EDIT: Edited to work with a custom array of strings. A NULL pointer indicates the end of the array. Although this declares an array of 4 strings, this method could be used with a dynamically sized array.
#include <stdio.h>
int main()
{
char* custom[4] = { "sleep", "30", "&", NULL };
int last;
for (last = 0; custom[last + 1]; last++);
printf("%i - %s\n", last, custom[last]);
return 0;
}
// ./a.out
// > 2 - &
For this to work for you, you would have to edit your program to explicitly include an extra NULL string in your char** when you build it. Without that indicator, the address after the last string wouldn't necessarily be NULL, so you could include garbage in the count or cause a segmentation fault.
Passing in a count like argc is the most common usage - but you say you don't have that.
Then the usual way is to have the last element of argv to point to NULL to indicate it is the last array element.
int argc = 0;
while (*argv++) {
argc++;
}
You may need to use strtok to tokenize the arguments and work through them until you have the last one.
Referemce for strtok.
char *argv[] = {"abc","123","xya"};
//prints the last string
printf("%s",a[strlen(*a)-1]);
// if you are sure that the array of strings ends with NULL
char *temp = 0 ;
while(*argv){
temp = *argv;
(*argv)++;
}
//temp has the last string
I would like to pass in arguments and output them as an array of characters or string. What is the easiest way to do this? Once I have them as an array of characters I want to be able to manipulate the array. I was able to pass them in and use a character pointer to traverse through the string but I'd like to use a char array. Is there any easy way to do this? Im pretty new to C, here is what I have so far.
if(argc != 3){
printf("incorrect number of arguments, program needs 3\n");
exit(1);
}
char s1[20];
s1 = (char*)argv[1];
char s2[20];
s2 = (char*)argv[2];
printf("String1 is %s\n", s1);
printf("String2 is %s\n", s2);
exit(0);
The strings pointed to by the argv array are modifiable, you can just modify the strings pointed to by the argv array, there is no need to copy them.
From the C standard:
(C99, 5.1.2.2.1p2) "The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination."
You can simply print the values of argv directly:
printf("String1 is %s\n", argv[1]);
printf("String2 is %s\n", argv[2]);
If you need to modify the strings, here is how you would do that
char *newString1 = malloc(strlen(argv[1]) + 1 + charactersToAdd); // add one for null termination.
strcpy(newString1, argv[1]);
// manipulate newString1 however you choose
printf("String1 is %s\n", newString1);
free(newString1);
argv[1] and argv[2] are already pointers to character arrays, so you can use those directly. Moreover (see #ouah's post), the strings are already mutable, so you might not need anything beyond this at all.
If you really want to have a scope-local array, you need to use the C99 feature called "variable-length arrays", since the string lengths are only known at runtime:
#include <string.h>
int main(int argc, char * argv[])
{
char s1[strlen(argv[1]) + 1];
strncpy(s1, argv[1], sizeof s1);
// ...
}
Alternatively you could malloc enough space for a copy of the string (say char * s1 = malloc(strlen(argv[1]) + 1);), but then you wouldn't have a local array after all (and you might as well use the original strings, unless you really wanted to make a copy).
argv is already char* (actually an array of an array), however, they are noted const as in "do not modify" ;). What you want is actually making a copy of them so you can manipulate them freely:
char str[40];
strcpy (str,argv[1]);
Now you can manipulate str as you wish.