In C, how can I convert a string to a character array? - c

I have the passed argument argv[1] in my C program, and I want to convert that string into a character array. How may I do this?
int main(int argc, char* argv[])
{
char c [] = argv[1]; // This is what I want to do...
}
EDIT:
What I'm trying to do is get certain characters from argv[1] and check if they are numbers. So, ideally, I would do something like:
int a = argv[1][2]
But this just runs into another problem - how can I check the type of a variable in C?

First of all, it already is a character array, NULL-terminated. You can simply choose to make another pointer to it, by saying char *c = argv[1];, or you can copy the entire string (null-terminator and all) into another array using the strcpy(char *destination, char *source)function http://www.cplusplus.com/reference/clibrary/cstring/strcpy/ like this:
char c[BUFFER]; //This has to be big enough to hold length + 1
strcpy(c, argv[1]);
Either approach is valid.

You can treat argv[1] as though it were an array of char (i.e., you can subscript it as argv[1][i]). You can pass it as an argument to any function that doesn't try to modify it (e.g., printf, strtol, strchr, etc.). You cannot write to it, though, so if you need to modify the contents for any reason (either directly or through a function like strtok or strcpy), you'll have to create a local copy and manipulate that.
If you are using C89 or earlier, use this method:
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
char *c = NULL;
if (argc >= 2)
{
c = malloc(strlen(argv[1]) + 1);
strcpy(c, argv[1]);
}
/**
* Do stuff with c
*/
free(c);
return 0;
}
If you are using C99, you can use a VLA:
#include <string.h>
int main(int argc, char **argv)
{
if (argc < 2)
return 0;
size_t len = strlen(argv[1]);
char c[len+1];
strcpy(c, argv[1]);
/**
* do stuff with c
*/
return 0;
}
Just remember a few things:
The type of argv is char **, not char *[N]; similarly, the type of argv[i] is char *, not char [M]. In most circumstances it doesn't matter; you can use a subscript operator on a pointer as though it were an array (array subscripting is defined in terms of pointer arithmetic), but remember that pointers and arrays are not the same thing and are not always interchangeable;
The value of argv[argc] is always NULL;
Except when it is the operand of the sizeof or unary & operators or is a string literal being used as an initializer in a declaration, an expression of array type is converted ("decays") from "N-element array of T" to "pointer to T", and the value of the expression is the location of the first element;
C doesn't have a string data type as such; strings are represented as 0-terminated sequences of char. String literals such as "hello" are stored in such a way that they exist over the lifetime of the program, and you can access them via a pointer value; attempting to modify them results in undefined behavior (i.e., don't do that).

argv[1][2] is of type char, always (<pedantry>accessing it causes undefined behavior if there are less than two arguments or if the length of the second argument is less than two - so its questionable whether it has a type in those cases</pedantry>). The character itself may represent a number however, and to check that, use isdigit() from header <ctypes.h>
#include <ctypes.h>
...
if (argc > 1) {
int digits = 0;
for (int i = 0, len = strlen(argv[1]); i < len; ++i)
if (isdigit(argv[1][i]))
digits++;
printf("Digits in %s: %d\n", argv[1], digits);
}

Technically, argv[1] is already a character array. There really isn't such a thing as a "string" in standard C.
What do you want to do with it? Do you just want a copy of it? In that case, you'd need to malloc some space for a new character array and then use "strcpy" to copy from argv[1] into your character array.

Related

Caesar Encryption in C

Hello I am working on a Caesar encryption program. Right now it takes as an input the file with the message to encrypt, the key
The input is currently in this format:
"text.txt", "ccc"
I need to convert this into taking a number so that it fits my requirements, so something like this:
"text.txt", "3"
Then i need to convert this "3" back into "ccc" so that the program still works. The logic being that 3 translates to the third letter of the alphabet "c", and is repeated 3 times. Another example would be if the key entered is "2", it should return "bb".
This is what i have so far but its giving me a lot of warnings and the function does not work correctly.
#include <stdio.h>
void number_to_alphabet_string(int n) {
char buffer[n];
char *str;
str = malloc(256);
char arr[8];
for(int i = 0; i < n; i++) {
buffer[i] = n + 64;
//check ASCII table the difference is fixed to 64
arr[i] = buffer[i];
strcat(str, arr);
}
printf(str);
}
int main(int argc, char *argv[]) {
const char *pt_path = argv[1]; //text.txt
char *key = argv[2]; //3
number_to_alphabet_string((int)key); //should change '3' to 'CCC'
}
Your problem is that you have a function
void number_to_alphabet_string(int n)
that takes an int but you call it with a char*
char* key = argv[2]; //3
number_to_alphabet_string(key);
My compiler says
1>C:\work\ConsoleApplication3\ConsoleApplication3.cpp(47,34): warning C4047: 'function': 'int' differs in levels of indirection from 'char *'
You need
char* key = argv[2]; //3
number_to_alphabet_string(atoi(key));
to convert that string to a number
With char *key = argv[2];, the cast (int) key does not reinterpret the contents of that string as a valid integer. What that cast does is take the pointer value of key, and interprets that as an integer. The result of this is implementation-defined, or undefined if the result cannot be represented in the integer type (a likely outcome if sizeof (int) < sizeof (char *)).
The C standard does not define any meaning for these values.
Here is a test program that, depending on your platform, should give you an idea of what is happening (or failing to happen)
#include <stdio.h>
int main(int argc, char **argv) {
if (sizeof (long long) >= sizeof (char *))
printf("Address %p as an integer: %lld (%llx)\n",
(void *) argv[0],
(long long) argv[0],
(long long) argv[0]);
}
As an example of implementation-defined behaviour, on my system this prints something like
Address 0x7ffee6ffdb70 as an integer: 140732773948272 (7ffee6ffdb70)
On my system, casting that same pointer value to (int) results in undefined behaviour.
Note that intptr_t and uintptr_t are the proper types for treating a pointer value as an integer, but these types are optional.
To actually convert a string to an integer, you can use functions such as atoi, strtol, or sscanf. Each of these have their pros and cons, and different ways of handling / reporting bad input.
Examples without error handling:
int three = atoi("3");
long four = strtol("4", NULL, 10);
long long five;
sscanf("5", "%lld", &five);
number_to_alphabet_string has a few problems.
malloc can fail, returning NULL. You should be prepared to handle this event.
In the event malloc succeeds, the contents of its memory are indeterminate. This means that you need to initialize (at least partially) the memory before passing it to a function like strcat, which expects a proper null terminated string. As is, strcat(str, arr); will result in undefined behaviour.
Additionally, memory allocated by malloc should be deallocated with free when you are done using it, otherwise you will create memory leaks.
char *foo = malloc(32);
if (foo) {
foo[0] = '\0';
strcat(foo, "bar");
puts(foo);
free(foo);
}
In general, strcat and the additional buffers are unnecessary. The use of char arr[8]; in particular is unsafe, as arr[i] = buffer[i]; can easily access the array out-of-bounds if n is large enough.
Additionally, in strcat(str, arr);, arr is also never null terminated (more UB).
Note also that printf(str); is generally unsafe. If str contains format specifiers, you will again invoke undefined behaviour when the matching arguments are not provided. Use printf("%s", str), or perhaps puts(str).
As far as I can tell, you simply want to translate your integer value n into the uppercase character it would be associated with if A=1, B=2, ... and repeat it n times.
To start, there is no need for buffers of any kind.
void number_to_alphabet_string(int n) {
if (1 > n || n > 26)
return;
for (int i = 0; i < n; i++)
putchar('A' + n - 1);
putchar('\n');
}
When passed 5, this will print EEEEE.
If you want to create a string, ensure there is an additional byte for the terminating character, and that it is set. calloc can be used to zero out the buffer during allocation, effectively null terminating it.
void number_to_alphabet_string(int n) {
if (1 > n || n > 26)
return;
char *str = calloc(n + 1, 1);
if (str) {
for (int i = 0; i < n; i++)
str[i] = 'A' + n - 1;
puts(str);
free(str);
}
}
Note that dynamic memory is not actually needed. char str[27] = { 0 }; would suffice as a buffer for the duration of the function.
A cursory main for either of these:
#include <stdio.h>
#include <stdlib.h>
void number_to_alphabet_string(int n);
int main(int argc, char *argv[]) {
if (argc > 1)
number_to_alphabet_string(atoi(argv[1]));
}
Note that with an invalid string, atoi simply returns 0, which is indistinguishable from a valid "0" - a sometimes unfavourable behaviour.
You can't use a cast to cast from a char array to an int, you have to use functions, such as atoi().
You never free your str after you allocate it. You should use free(str) when you no longer need it. Otherwise, it will cause a memory leak, which means the memory that you malloc() will always be occupied until your process dies. C doesn't have garbage collection, so you have to do it yourself.
Don't write things such as char buffer[n];, it can pass the compile of GCC, but it can't in MSVC.
And that isn't the stander way of declaring an array with variable length. use
char* buffer = malloc(n);
//don't forget to free() in order to avoid a memory leak
free(buffer);

error: expected expression before ']' token when passing an array as an arguement in C

I am new to C. Was writing this so it takes the strings from the passed array and makes it a single sentence. But I got this error, I am not good with arrays in C. I can use some help from you guys. I did search an answer for this and couldn't find.
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char smash(char arr[20][20]) {
char tmp[sizeof(arr)/sizeof(arr[0])];
for (int i=0; i < sizeof(arr)/sizeof(arr[0]); i++) {
strcat(tmp, arr[i]);
strcat(tmp, " ");
}
return tmp;
}
int main(){
char list[][6] = {"hello", "world"};
printf("%s", smash(list[]));
}
Error
error: expected expression before ']' token
printf("%s", smash(list[]));
^
There are quite a number of errors in this small piece of code.
First, to address the compiler error: list[] is not a valid expression. If you want to pass list to the function, leave the braces out:
printf("%s", smash(list));
This will then bring up another error. The function is expecting a char [20][20] as it's argument, but that's not what you're passing in. Since arrays as parameters are converted to a pointer, the argument type is actually char (*)[20] i.e. a pointer to an array of char of size 20. Note also that this conversion only occurs for the outermost array dimension, not all.
Since you're passing in a char [2][6] which gets converted to a char (*)[6] this is a type mismatch. So change the parameter to char arr[][6].
Then you're attempting to get the size of the array parameter inside of the function:
sizeof(arr)/sizeof(arr[0])
Since arrays cannot be directly passed to a function due to the conversion mentioned earlier, arr is actually a pointer and not an array, so you won't get the result you expect from this. You'll need to pass the number of array elements as a separate parameter.
Then you're calling strcat on tmp. This function will only work if the destination already has a null terminated string in it. Since tmp was not initialized or written to prior to the first call to strcat, you end up reading uninitialized bytes and potentially past the end of the array which will trigger undefined behavior.
This can be fixed by setting the first byte of the array to 0 before the loop to make it an empty string:
tmp[0] = 0;
for ...
Then there's the problem with the return type. The function is declared to return a char but you're giving a char * to the return statement, and at the point the function is called it is passed to printf where the %s format specifier is expecting a char * parameter.
So change the return type of the function from char to char *.
Finally, you're returning a pointer to a local variable in the function. This variable's lifetime ends when the function returns, so the returned pointer is invalid and using it will also trigger undefined behavior.
You'll need change tmp to a pointer and dynamically allocate memory for it using malloc. This also means you'll need to save the return value of the function in a separate variable which you can then pass to printf to print and then pass to free to free the memory.
After making all this changes, the resulting code should look like this:
char *smash(char arr[][6], int len) {
// enough for len strings plus len spaces
char *tmp = malloc(sizeof(arr[0]) * len + len + 1);
tmp[0] = 0;
for (int i=0; i < len; i++) {
strcat(tmp, arr[i]);
strcat(tmp, " ");
}
return tmp;
}
int main(){
char list[][6] = {"hello", "world"};
char *result = smash(list, sizeof(list)/sizeof(list[0]));
printf("%s", result);
free(result);
return 0;
}

Reverse order in array of char in C

The pointers confuse me a lot. I have a function that takes as arguments argc (the number of argument that are strings + 1 that is the name of the code) and char* argv[], that, if I understood well, is an array of pointers. Now as result I need to print on each line the argument (string) and the reversed string. This means that if I pass as arguments hello world, I need to have:
hello olleh
world dlrow
I tried to implement a part of the code:
int main(int argc, char *argv[])
{
int i = 1;
int j;
while (i < argc)
{
while (argv[i][j] != 0) {
printf("%c", argv[i][j]);
j++;
}
i++;
}
return 0;
}
}
And now I'm literally lost. The inner loop doesn't work. I know that argv[i] pass through all my arguments strings, but I need obviously to enter in the strings (array of chars), to swap the pointers. Also I don't understand why the difference between argv[0] and *argv, because in theory argv[0] print the first element of the array that is a pointer, so an address, but instead of this it prints the first argument.
char* argv[] is a "array of pointers to a character" It's important to learn how to read types in C; because, those types will enable / thwart your ability to do stuff.
Types are read right to left. [] is a type of array, with an unspecified number of elemnts * is a pointer type, char is a base type. Combine these, and you now have "array of pointers to a character"
So to get something out of argv, you would first specify which element it is in the array. argv[0] would specify the first element. Let's look at what is returned. Since the array is not part of the result, the answer is "a pointer to a character"
char* line = argv[0];
would capture the pointer to a character, which is stored in argv[0].
In C a char* or a "pointer to a character" is the convention used for a string. C doesn't have a new type for "string"; rather it uses pointers to characters, where advancing the pointer eventually runs into the \0 character that signals the string's end.
int main(int argc, char* argv[]) {
int index = 0;
while (index <= argc) {
char* line = argv[index];
printf("%d, %s\n", index, line);
index++;
}
}
should dump the arguements passed to your program. From there, I imagine you can handle the rest.
Notice that I never converted the pointer to an array. While arrays can be used as pointers if you never specify the index of the array, in general pointers can't be used as arrays unless you rely on information that isn't in the type system (like you clearly grabbed the pointer from an array elsewhere).
Good luck!
---- Updated to address the question "How do I reverse them?" ----
Now that you have a simple char* (pointer to a character) how does one reverse a string?
Remember a string is a pointer to a character, where the next characters eventually end with a \0 character. First we will need to find the end of the string.
char* some_string = ...
char* position = some_string;
while (*position != 0) {
position++;
}
// end_of_string set, now to walk backwards
while (position != some_string) {
position--;
printf("%c", *end_of_string);
}

warning: assignment makes integer from pointer without a cast, sorting arguments

I know this was asked a few times, but I still do not fully understand the issue.
I have an assigment where I need to save and sort the arguments.
int main(int argc, char* argv[])
{
int c;
char* s = malloc(argc * sizeof(char));
extern char *optarg;
extern int optind;
extern int optopt;
while ( (c = getopt(argc, argv, ":adh")) != -1) {
s[argc] = argv;
switch (c) {
case 'a': printf("a\n");
break;
case 'd': printf("d\n");
break;
case 'h': printf("h\n");
break;
}
}
return 0;
}
I know that it has something to do with me saving a pointer to an integer or not doing it.
char* argv[] is what? An array of pointers?
And s is only an array of chars?
char* argv[] is what? An array of pointers?
When such a declaration appears in a function prototype, as in your code, it is equivalent to char **argv. That's a pointer to a pointer to char. In this particular case, the pointed-to pointer is the first element of an array of pointers.
And s is only an array of
chars?
As you have declared an initialized it, s is a pointer to char, and in particular, it points to the first char in a dynamically allocated block. You can use the block via s as if it were an array of char, but it is not technically an array, and s definitely is not an array. Although related, pointers and arrays are very different things.
The compiler should have told you at least on which line the error occurs, but you did not pass that information on to us. Nevertheless, I think I can guess. This line ...
s[argc] = argv;
... is nonsense. Since s is a pointer to char, s[argc] designates one char (and in C, char is among the integer data types). On the other hand, argv is a pointer (to pointer to char). Although C permits pointers to be converted to integers, it is rarely useful to do so, and anyway, a conforming program must use a cast to perform such a conversion. Since you don't actually use s for anything, your best bet is probably to just remove that line.
For what it's worth, if you wanted to set s to point to one of the command line arguments, say the second, the syntax would be
s = argv[2];
(The zeroth element of argv is conventionally the name of the program; the arguments start at index 1.) But if you intend to do that then you don't need to malloc() any memory for s; whatever you do allocate for it is leaked when you assign a new value to it.
char *argv[] is a pointer to an array of strings. AKA char **argv
int argc is an integer count of the number of strings on the command line, including exe name.
Note also that the length of each string in argv[] has nothing to do with the value of argc. The strings can be as short as two characters, such as a\0 or as long as (or longer than) 1000 characters.
So the statement char* s = malloc(argc * sizeof(char)); will not do what you are thinking it will do.
First it is the form of an expression that will create some space for only one string, not argc of them.
Second, if your command line included 3 item, ( argc == 3 ) and one of the arguments was a string of length 9, say arguments, then your malloc statement would create space for 1 string, with only 3 characters. Not big enough to contain the string `arguments\0', not to mention the other two.
Use something like the following to determine the length of the longest of the argc strings:
int len = 0, lenKeep = 0;
for(i=0;i<argc;i++)
{
len = strlen(argv[i] > len)
if(len > lenKeep) lenKeep = len;
}
Now, lenKeep + 1 has been established as the length needed to contain the longest string (+ 1 for the NULL character, which strlen(...) does not include in its count.). This can be used, along with knowing the number of strings, argc, to allocate memory for each of them.
For example:
int main(int argc, char* argv[])
{
...
char **string = Create2DStr(argc, lenKeep + 1);//will create space
//sufficient to contain
//strings of your command line
...
}
Where Create2DStr(...) could be defined as:
char ** Create2DStr(ssize_t numStrings, ssize_t maxStrLen)
{
int i;
char **a = {0};
a = calloc(numStrings, sizeof(char *));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(maxStrLen + 1, 1);
}
return a;
}

Building char array from a string (C)

I am writing a simple function in C that should build a char array from string "abc" – so it should build {'a','b','c'} – and return a pointer to that array. Here is my code for this function:
char * makeArr()
{
static char arr[3];
sprintf(arr, "%s\n", "abc");
return arr;
}
Problems occur when I call this method in main:
int main(int argc, char *argv[])
{
char *arr[3];
arr = makeArr();
return 0;
}
The compiler is complaining about casting / conflicting types. I've been playing with pointers, casting and dereferencing for quite a while now, but can't seem to get it to work. Please let me know where my logic is wrong.
Hmm ... there are several errors in this code. Let's start with the most obvious your compiler complains about:
char *arr[3];
This line declares arr to be an array of three pointers to char. What you return from your function is a single pointer to a char -> doesn't match.
Next:
static char arr[3];
sprintf(arr, "%s\n", "abc")
Here you reserve 3 chars. the sprintf() will write 5 chars. %s is replaced by the 3 characters in your string literal "abc". You add a newline character and then a 0 is added as the marker for the end of the "string". Makes 5. This btw is undefined behavior. You write past the end of your array. Code like this can be compiled, but there's no guarantee at all about what will happen at runtime.
Doing a cut here. You should read about arrays and pointers in C. If the text you're reading claims they are the same ... stop right there and find a better text. They aren't.
I'll try to explain this here briefly, so it's suitable for the Q&A style.
An array in C indeed is a contiguous space of several values. char arr[3] means a variable that holds 3 chars.
On the other hand, a char * is just a pointer pointing to a char -- this could be the first element of an array.
In C, you can't pass arrays as function parameters, and you can't return arrays from a function. Trying to do so leads to an implicit conversion: What is actually passed is a pointer to the first element of that array.
I think the last bit of information missing is what a string literal in C is: it's an array (anonymous, e.g., it doesn't have a name) containing all the characters in the double quotes plus a 0 appended. The 0 marks the end of a "string" in C.
In an expression, a string literal evaluates to a pointer to the first element.
So, something like this:
char *foo = "bar";
will lead to foo pointing to the b of the array. It's like writing
static const char no_name_0[] = { 'b', 'a', 'r', 0 };
char *foo = &(no_name_0[0]);
Among other things, you confused:
char arr[3]; // array of 3 chars.
and,
char *arr[3]; // array of 3 pointers to char.
In main(), you should only write char *arr;
Firstly, char arr[3]; is too snall to store "abc\n". It must have at least 5 elements including terminating null-character.
Then, char *arr[3]; is a 3-element array of char*.
You should assign makeArr()'s return value (it has char* type) to arr[0] or another element, or you should change the type of arr in main function to char*, which is the same type as makeArr()'s return value.
Moreover, this makeArr() doesn't make any array and returns (a pointer to) the existing array. Yoy should use malloc() to "make an array".
UPDATE:
Assigning a value of char* to the array char arr[10]; seems invalid in C.
You should use strcpy() or strncpy() (safer than strcpy()) to copy the string stored in the array between arrays.
Pass the array as an argument and modify it in the called function, would be easier. If you're statically creating the array and there's no need to allocate memory, don't, just pass around your pointers to the functions to be modified by reference
void makeArr(char arr[]){
sprintf(arr, "%s\n", "abc");
}
Simply pass the existing declared array to the makeArr function...
int main(int argc, char *argv[]) {
char arr[10];
makeArr(arr);
return 0;
}
You couldn't assign the result of makeArr to arr. I guess that's your casting error. Oversimplifying, arr points to the place on the stack where the array of 10 characters is allocated. So, I'd pass in arr to makeArr as a char*. So, you'd end up with something like this:
#include <stdio.h>
char * makeArr(char *arr)
{
sprintf(arr, "%s\n", "abc");
return arr;
}
int main(int argc, char *argv[])
{
char arr[10];
makeArr(arr);
printf("%s\n", arr);
return 0;
}

Resources