unable to get filename from argv[1] in C - c

I'm trying to make a program which makes a copy of the file you put in, only then with a reversed filename (eg. input.txt = txt.tupni).
I start my program with
int main(int argc, char **argv) {
When I use printf("%s",argv[1]) I can see the file name which has been put in. However, when I try to manipulate it I can't get it to work.
char name = argv[1] doesnt work,
neither does char name[] = argv[1] work
All I want is either a char array or a piece of malloc memory which has all of the characters.

argv is of type char **, so argv[1] is of type char *. So that's the type of the variable you want to assign this to.
char *name = argv[1];
You can't declare name as char [] and initialize it with a char *. Only a string literal may be used for initialization.
If you want to make a copy of the string rather than have another pointer to it, you can use strdup which allocates memory for the copied string and copies it over.
char *name = strdup(argv[1]);
Don't forget to free it when you're done with it.

You need to use a function like strcpy to accomplish this, as well as know the string length.
Here's what you do:
int len = strlen(argv[1])
char *buffer = (char*)malloc(len + 1);
if(buffer != NULL)
{
strcpy(buffer, argv[1]);
// copy the file etc.
}

Related

Function return value can't be assigned to a const char value

I am using OpenGL, don't worry my problem is with C and not something related to OpenGL. In OpenGL, we have something called shaders. It is a text file. All I want to do is to read that text file and pass it to a function that accepts only const char * const*. (eg. func(&shaderSource) and shaderSource must be const char* shaderSource.). I just want this terminology with multiple files. Can I? I saw people doing this with C++, but I chose C over C++ in the project. Here is some of my failed attempts.
char vertexShaderContent[1000] = readfile("Shader/default.frag.txt");
const char *vertexShaderSource;
strcpy(vertexShaderSource, vertexShaderContent);
Here I tried to get a new variable (By the way this is in the main function) that executes the function and gets the return value of that function. Now I did copy that string (using strcat) to assign the value of vertexShaderContent to vertexShaderSource. By the way here is my readfile code:
char *readfile(const char* filename) {
char *res = malloc(sizeof(char *) * 100);
char *word = malloc(sizeof(char *));
FILE *file = fopen(filename, "r");
while (fgets(word, sizeof(word), file) != NULL) {
strcat(res, word);
}
strcat(res, "\n\0");
fclose(file);
return res;
}
Summary
All my problem is that I want to pass a char* to a function accepting const char*s. If I can't, is there is any way I can get this 'multiple' files to work?
Thanks.
In char vertexShaderContent[1000] = readfile("Shader/default.frag.txt");, readfile returns a pointer to char, but vertexShaderContent is an array of char. To initialize an array, one needs to provide values for each element to be initialized. A pointer to char is not a correct type for initializing char values.
What may work here is char *vertexShaderContent = readfile("Shader/default.frag.txt");. That defines vertexShaderContent to be a pointer to the memory returned by readfile. However, it is not clear what you want to do, because the code that follows it is confusing:
const char *vertexShaderSource;
strcpy(vertexShaderContent, vertexShaderSource);
This would overwrite the data at vertexShaderContent with new data, so it loses the data that readfile returned. And it attempts to copy from vertexShaderSource, but vertexShaderSource has not been set to point to anywhere. Its value is indeterminate. This strcpy cannot do anything useful. Since we do not know what you are trying to do here, we cannot recommend a solution.
These lines in readfile are incorrect:
char *res = malloc(sizeof(char *) * 100);
char *word = malloc(sizeof(char *));
The first allocates space for 100 char *. To allocate space for 100 char, use char *res = malloc(100 * sizeof *res);.
The second allocates space for one char *. But it looks like you want space for one “word”, which would likely be some varying number of characters. Maybe you would want to start with space for at least 100 characters:
char *word = malloc(100 * sizeof *word);
That could help get the code going at first, although a good eventual solution would ensure the allocated spacer could not be overflowed.
In strcat(res, word), the data pointed to by res has not yet been initialized. Before using strcat, you must have some string in the destination. That can be the empty string, which you can create by putting a null terminator character in res:
*res = '\0';
All my problem is that I want to pass a char* to a function accepting const char*s.
Nothing in the question shows any attempt to pass a char * for a const char * parameter that would not work, except for the issues noted above.

Storing char in array with strcpy

char strr[10];
strcpy(strr, argv[1]);
This works fine for storing an entire argument but how do i use the same technique
if i want to store a certain char from the first argument.
strcpy(strr, argv[1][1]);
This wont work ofcourse since its a char, so im wondering how else i can do it
EDIT:
i just used char strr[10]; as an example of an char array. Please dont pay attention to the size of it.
You can't store a char in array using strcpy. strcpy is for strings - not chars.
But you can do it in another way.
It's very simple:
char strr[2] = { 0 }; // Make strr a string that can hold 1 char and a
// string termination. Initialize to zero.
strr[0] = argv[1][1]; // Copy the second char of the string pointed to by
// argv[1] to the first char of strr
Now sttr is a string that holds just one char (and the mandatory string termination).
Besides this code, you need to ensure that argv[1] is valid and that argv[1][1] is valid.
Something like:
char strr[2] = { 0 }; // Make strr a string that can hold 1 char and a
// string termination. Initialize to zero.
if (argc > 1 && strlen(argv[1]) > 1)
{
strr[0] = argv[1][1]; // Copy the second char of the string pointed to by
// argv[1] to the first char of strr
}

How do I change fill this string through a pointer which points to another pointer which then points to this string

I'm not sure sure about how I should be doing this. This is my code below. The function readLine reads the line from a file and stores it in string though ptr2. I have a feeling im messing up the stars. Could someone please explain to me what would be the right way to do this.
int main(int argc, char **argv)
{
FILE *fp;
fp = fopen("testFile.txt","r");
if( fp == NULL ){
printf("Error while opening the file.\n");
}
char string[75];
char *ptr1 = &string[0]; //want ptr1 to point to string
char *ptr2 = &ptr1[0]; //want ptr2 to point to ptr1
readLine(fp,**ptr2); //want to send ptr2 pointer so that function read the file and add it to string can be edited through the pointer.
printf("%s", **string);
fclose(fp);
return 0;
}
readLine(FILE *fp, char **string){
fgets(**string, 75, fp);
}
Edit: I know there are much better ways of doing this. I have done it this way just to help explain the situation i am trying to understand which is how do pass a pointer to a pointer to a function to edit the string.
If you have char *p1 = &string[0], then you only need to assign the value of p1 to the p2: char *p2 = p1.
I think the asterisks are confusing you. If you have an asterisk in variable declaration, like this: char *p2, it means that variable p2 is a pointer, but when you have asterisk in another place, such as *p2 = 'c', the you dereference the pointer, that is, you save the value of 'c' directly to the memory location where p2 points.
So, here is your code, fixed:
int main(int argc, char **argv)
{
FILE *fp;
fp = fopen("testFile.txt","r");
if( fp == NULL ){
printf("Error while opening the file.\n");
}
char string[75];
char *ptr1 = string;
char *ptr2 = ptr1;
readLine(fp, ptr2);
printf("%s", **pbuff); // I don't know what pbuff is
fclose(fp);
return 0;
}
readLine(FILE *fp, char *string){
fgets(string, 75, fp);
}
Keep in mind that I didn't compile this because I can't right now, using my sister's computer and she is not a programmer. :)
The difficulty you are having, and the question, seems to stem from an unfamiliarity you have with pointers, and how they are passed as parameters to a function. When you declare a character array, e.g. char string[75]; the value held by string is the address to the first character in, (or beginning memory address) for, the statically declared 75-char array. (it itself is a pointer).
When you then declare another pointer to the array, all you need do is assign the value held by string (a pointer to the address of string[0]) to any new pointer created. e.g.:
char *ptr1 = string;
char *ptr2 = ptr1;
It is exactly the same as declaring both pointers and then setting them equal to string, e.g.:
char *ptr1, *ptr2;
ptr1 = ptr2 = string;
When you are dealing with pointers, they are nothing more than a variable that holds the address to something else as their value. Therefore, after the assignment above ptr1, ptr2 and string all hold the same value (that being the address to the first character in the 75-char array).
Now when you pass a pointer as a parameter to a function, the function receives a copy of the pointer, just as a function receives a copy of any other variable. This is important. If the pointer is already declared and allocated (either statically or dynamically), you can simply pass a copy of the pointer and the function will still receive its value (the address of the array). There is no need to pass the address of the pointer in that case, (e.g. char **) passing the pointer itself (even though passed as a copy) its value still provides the needed address of the array.
The only case where you need to pass the address of the pointer are in the cases there the pointer is unallocated (i.e. NULL - holding no address), or where the address of the pointer itself is important (i.e. passing a pointer to a linked-list where you intend to change the first node in the list, etc.) In those cases, then for the calling function to maintain a correct reference to the newly created pointer or the new address for a list (if you delete/add a new first node) -- you must pass the address of the pointer to the function. In your case, that is not required.
In fact, in your case, it doesn't matter which you pass to readLine (ptr1, ptr2, or string) as all hold the exact same value -- the beginning address of an allocated array. You are free to read values using either one, as the characters you read will all be stored beginning at the exact same address.
With that in mind, you could do something similar to the following:
#include <stdio.h>
char *readLine (FILE *fp, char *string);
int main (int argc, char **argv) {
char string[75] = {0};
FILE *fp = NULL;
char *fn = argc > 1 ? argv[1] : "testFile.txt"; /* filename */
char *ptr1, *ptr2;
ptr1 = ptr2 = string;
if (!(fp = fopen (fn, "r"))) { /* validate file open */
fprintf (stderr, "error: file open failed '%s'.\n", fn);
return 1;
}
if (readLine (fp, ptr2))
printf ("%s\n", ptr1); /* any reference to string will work */
else
fprintf (stderr, "error: readLine failure.\n");
fclose(fp);
return 0;
}
char *readLine (FILE *fp, char *string)
{
return fgets (string, 75, fp);
}
Sample Input File
$ cat ../dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
Use/Output
$ ./bin/readln ../dat/captnjack.txt
This is a tale
When you declare:
char string[80];
string IS a pointer to the first element in the array of character.
That being said, I don't understand the roles of both ptr1 and ptr2. You can simple use fscanf if you want to read into a string.
char string[80];
FILE * pFile;
pFile = fopen ("myfile.txt","r");
fscanf (pFile, "%s", string);
You'll need to check the return value of fopen and fscanf of course. Regarding the C function readline, it exists in two places libreadline and libedit. If you are implementing your own readLine, it may also have problems.
Addendum: If you want to modify a string inside a function, say readLine
void readLine(char **arr){
*arr = "efgh";
}
int main(int argc, const char** argv){
char *str = "abcd";
printf("%s\n",str);
readLine(&str);
printf("%s\n",str);
return 0;
}
This passess the address of the pointer str (readLine(&str)), and the pointer itself is changed in the function(*arr = "efgh").

Dynamically allocated string from command line argument

I'm looking to process a string passed via a command line argument with a for loop in C. I'm wondering if this would be the correct way.
main(int argc, char * argv[])
{
char * somestring;
somestring = malloc( (strlen(argv[1]) + 1) * sizeof(char) );
somestring = argv[1];
...
}
or would C allocate the appropriate memory if I did:
char * somestring;
somestring = argv[1];
If you want to copy an argument in your own allocated memory then you have to write
int main(int argc, char * argv[1])
{
char * somestring;
somestring = malloc( strlen( argv[1] ) + 1 );
strcpy( somestring, argv[1] );
...
}
otherwise statement
somestring = argv[1];
results in a memory leak.
Also do not forget to free the memory when it will not be needed any more.
Take into account that though this record
int main(int argc, char * argv[1])
is valid it is better to write
int main(int argc, char * argv[])
because your intention by specifying char * argv[1] is not clear
If you need to preserve a transient string then yes you need to allocate memory, copy it into the new buffer (via strcpy-like function) and latter deallocate that buffer.
But in this case, the command line arguments are not transient. They are available for the whole lifetime of the process. Therefore it is enough to just remember the pointer to them. So something like this would be enough:
const char* firstParameter = nullptr;
int main(int argc, char* argv[])
{
if (argc > 1) firstParameter = argv[1];
}
A good way would be allocating the memory for the pointer and use strcpy function to copy the contents.
For example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
char *somestring;
if(argv[1] == NULL)
{
puts("Argument 1 is not specified.");
exit(1);
}
somestring = malloc( strlen(argv[1])+1 );
strcpy(somestring, argv[1]);
printf("%s\n",somestring);
return 0;
}
Also before allocating the memory for pointer, first check if argv[1] is not NULL.
Fisrt of all this is a wrong way of copying a string into another string.
You have done memory allocation correcly but your method of copying a string into another is wrong. You have allocated memory for string and collected its address into somestring. Now you are assigning argv[1] to it which is address of command line argument vector which is 2D array actually. So you should use strcpy() to copy string.
Or if you want just base address of string use char pointer instead and assign argv[1] to it. But it is of no use.
P.S. passing command line argument like you are doing is not recommended as all arguments are stored in argument vector argv which is 2D array. So if you are passing only one string then it is okay but if you are passing more than one strings then use char **argv instead.

C Pointers and Arrays Incompatible Types

So I was wondering why I can't do this.
int main(int argc, char **argv){
FILE *src;
char filePath[261];
filePath = argv[1];
The last line is where there is a compiler error. What's the difference between char[] and char*? How would I fix this code so I can set filePath equal to argv[1].
Thanks in advance.
Use
strcpy(filePath, argv[1]);
and live happy. Don't forget to check argv[1] for being NULL and don't forget to see if argc is > 1.
Your filePath variable is a fixed-size array which is allocated on the stack and argv[i] is a pointer to some memory in the heap. Assigning to filePath cannot be done, because filePath is not a pointer, it is the data itself.
Because filePath is an array and it's not allowed to modify the address of an array in C.
You can use the string family to copy the strings.
You need to have:
FILE *src;
char *filePath;
filePath = argv[1];
since filePath must point to argv, not to an array of 261 bytes. If you want, you can copy the argumenti into the array:
FILE *src;
char filePath[261];
strcpy(filePath, argv[1]);
or better, to avoid risking copying more bytes than you have available (which would result in disaster):
FILE *src;
char filePath[261];
strncpy(filePath, argv[1], sizeof(filePath));
or again
#define MAX_FILESIZE 261
FILE *src;
char filePath[MAX_FILESIZE];
strncpy(filePath, argv[1], MAX_FILESIZE);
Q: What's the difference between char[] and char*?
A: Often times, you can use them interchangeably.
But here, you're "attempting to use an array name as an lvalue" :)
Here's a good explanation:
http://eli.thegreenplace.net/2011/12/15/understanding-lvalues-and-rvalues-in-c-and-c/
Here's a short summary of "what's legal, and what's not":
http://msdn.microsoft.com/en-us/library/bkbs2cds.aspx

Resources