Store a Char from command line to Char array in C - c

I'm having trouble when I try to store the stdin in a program inside char array variable.
It throws a segfault when it goes by these lines:
procNames[processNumber] = argv[1];
and
strcpy(procNames[processNumber], proc[0]);
How can I store the chars in the array procNames?
The usage is:
(stdin) <CHAR>: <NUMBER>
I want to store every <CHAR> and every <NUMBER> introduced by order. The <NUMBER> stores without erros, the <CHAR> storage throws the segmentation fault.
char line[80],proc[80];
// Storing
char procNames[80];
int procPorts[80];
// To iterate
int processNumber = 0;
int actualProcessNumber = 0;
[...]
for(;fgets(line,80,stdin);) {
sscanf(line,"%[^:]: %d",proc,&port);
[...]
if(strcmp(proc,argv[1]) == 0) {
if (repeatedProc == false) {
procNames[processNumber] = argv[1];
procPorts[processNumber] = puerto_udp;
actualProcessNumber = processNumber;
processNumber++;
}
} else {
if (repeatedProc == false) {
strcpy(procNames[processNumber], proc[0]);
procPorts[processNumber] = port;
processNumber++;
}
}
}
Can someone please help me?

Regarding the issues you get:
1.
You need
char procNames[N][80];
instead of
char procNames[80];
where N gives the amount of strings to hold in procNames. [80] - 1 just specifies the maximum amount of characters possible in each string.
2.
You cannot assign arrays with strings by the = operator in C. Use strcpy() instead.
Replace
procNames[processNumber] = argv[1];
with
strcpy( procNames[processNumber], argv[1] );
3.
strcpy(procNames[processNumber], proc[0]);
The second argument of needs to be a pointer to char, proc[0] is of type char. Use proc only.
proc has no string in it to copy. Use at least char proc[80] = ""; to not get a runtime error.

Your procNames is an array of characters, not an array of pointers. Arrays cannot be assigned, just copied, and procNames[processNumber] = argv[1] should actually issue a warning / an error.
Further, as you intend to have an array of - let's say - 10 such names, you probably mean
char procNames[10][80];
Then you can write
strcpy(procNames[processNumber],argv[1]);
to copy the contents of the string argv[1] points to.
Furhter, in order to avoid that you exceed the length of a procNames-entry, I suggest to use
strncpy(procNames[processNumber],argv[1],80);

You defined char procNames[80]; which means it's a string that can hold 80 characters (also counting the 0-terminator at the end).
Later one you're doing this procNames[processNumber] = argv[1]; where procNames[processNumber] points to a character and argv[1] is a string holding the first command line parameter. So in fact you're trying to assign a pointer to a char.
Your compiler must have at least warned you about this.
Make sure to really look at compiler output as it often tries to tell you what you are doing wrong.

Related

Passing char array to a function by reference when the size is not known

I am learning about pointers and char arrays and was wondering if you could help me find the optimal solution here. I want to avoid using malloc hence I chose to pass a char array to a function by reference where the values are getting filled.
In my main.c
char saved_networks[100]; // create an array to save data
readFile123(SPIFFS, "/wifi.txt",saved_networks);
Serial.print("saved networks=");
Serial.println(saved_networks);
And the function:
void readFile123(fs::FS &fs, const char *path, char* return_data)
{
int n=0;
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if (!file || file.isDirectory())
{
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while (file.available())
{
char c = file.read();
delayMicroseconds(100);
Serial.print(c);
//strcat(return_data, &c); //returns meditation error
return_data[n]=c;
n=n+1;
}
file.close();
}
In the program above, I create a char array size of 100 and pass it to the function. Inside a function, I read data inside my SPIFFS file system and then assing whatever string I found there to my char array. The code above works however I have 3 questions:
1. Why I cannot use strcat(return_data, &c);
The causes the cpu to crash and return an error:
Stack smashing protect failure!
abort() was called at PC 0x40137793 on core 1
ELF file SHA256: 0000000000000000
2. Why I cannot declare my char array as following : char* saved_networks;. If I do that, my microcontroller will crash and return an error:
Read from file: TGuru Meditation Error: Core 1 panic'ed (StoreProhibited). Exception was unhandled
3. What is the most optimal way to solve this problem? Since I do not know what will be the maximum size of the data that I read form SPIFFS, simply declaring it size of 100 may not be enough. Is there any way to declare it dynamically ? I assume the only way to do that is by using malloc? Is that true?
strcat(return_data, &c) is a <string> function, and as such, it expects actual strings and not char arrays.
In your example, you pass the address of a char, which can be interpreted as a char array of size 1.
What is the difference?
Well, strings are null terminated char arrays, which means their last valid element is a '\0', everything after that char is ignored by those str functions.
char* saved_networks; Declares a variable that can store an address of type char, you still have to allocate space! That space's address will then be stored in saved_networks.
You can try to find out how big the file is before reading it. Or you can incrementally read it.
Since you're using C++ you could also use std::string
Edit: when you pass the name of an array it is already a reference, so I'd say you're passing it correctly already, just need to be careful you don't exceed the space allocated (100 chars in this case).
To make it more clear, let me show you some examples of syntatic sugar:
char saved_networks[100];
saved_networks == &saved_networks[0]; // true
saved_networks[0] == *saved_networks; // true
saved_networks[50] == *(saved_networks + 50); // true
&saved_networks[50] == saved_networks + 50; // true
The +50 depends of the array type: in this case it means 50 bytes because chars are 1 byte each.
Edit 2:
"h" in reality is more similar to:
char const arr[2] = {'h', '\0'};
Which implies that " is used for strings and ' for chars!
This is important because str functions are expecting strings to be null terminated, or else there will be invalid memory accesses from infinite loops.
I think that's what you were missing and now you'll be able to better understand my first point.
Pass the length of the array:
size_t len = sizeof(saved_networks)/sizeof(*saved_networks);
char *saved_networks = readFile123(SPIFFS, "/wifi.txt",saved_networks, &len);
And then make sure that the length is not exceeded:
char *readFile123(fs::FS &fs, const char *path, size_t *lenp)
{
size_t chunksize = *lenp; // You can pass in chunksize you want to use
size_t n = 0;
size_t chunk_len = 0;
char *return_data = malloc(chunksize);
return_data[0]=0;
*lenp = 0;
...
while (file.available())
{
char c = file.read();
delayMicroseconds(100);
Serial.print(c);
return_data[n]=c;
n=n+1;
chunk_len++;
if (chunk_len == chunksize-1)
{
return_data = realloc(return_data, n+chunksize);
chunk_len = 0;
}
}
return_data[n]=0;
*lenp = n;
return return_data;
}

In C, I'm unable to copy a single element of an array of character strings to another string

I have a string "prompt" that holds a string of characters. The user must be able to change the prompt with user input, which I've collected and separated (using whitespace as a delimiter) into an array of char strings (tokens).
For example, assume:
char **tokens[2] = {"setprompt", "newprompt"};
char *prompt = "oldprompt";
if(strcmp(tokens[0], "setprompt") == 0)
{
strcpy(prompt, tokens[1]);
}
The strcmp() function works perfectly fine, however when it reaches strcpy(), the element in tokens[1] (which is the string "newprompt") isn't copied into the string prompt. This is my problem.
I've tried troubleshooting, in addition to using strncpy() instead but I think there's an issue somewhere with my declarations of each variable/pointer. Any assistance or ideas would be great.
Note: in my actual program, the tokens array doesn't have a definitive size of 2. This example is modified for simplicity. Thanks!
Your issue is this line:
char *prompt = "oldprompt";
It points to constant memory and cannot be modified (the way it is defined). Consider leaving it read-only and creating your own buffer instead for copying and modifying Something like:
#define MAX_STRING_SIZE 255
char *tokens[2] = {"setprompt", "newprompt"};
char *prompt = "oldprompt";
char myBuffer[MAX_STRING_SIZE];
strcpy(myBuffer, prompt );
if(strcmp(tokens[0], "setprompt") == 0)
{
strcpy(myBuffer, tokens[1]);
}

initialization makes integer from pointer without a cast [enabled by default]

i just started to learn how to program and i encountered this error that goes like this: "initialization makes integer from pointer without a cast [enabled by default]"
What is the problem?
// This program pairs three kids with their favorite superhero
#include <stdio.h>
#include <string.h>
main()
{
char Kid1[12];
// Kid1 can hold an 11-character name
// Kid2 will be 7 characters (Maddie plus null 0)
char Kid2[] = "Maddie";
// Kid3 is also 7 characters, but specifically defined
char Kid3[7] = "Andrew";
// Hero1 will be 7 characters (adding null 0!)
char Hero1 = "Batman";
// Hero2 will have extra room just in case
char Hero2[34] = "Spiderman";
char Hero3[25];
Kid1[0] = 'K'; //Kid1 is being defined character-by-character
Kid1[1] = 'a'; //Not efficient, but it does work
Kid1[2] = 't';
Kid1[3] = 'i';
Kid1[4] = 'e';
Kid1[5] = '\0'; // Never forget the null 0 so C knows when the
// string ends
strcpy(Hero3, "The Incredible Hulk");
printf("%s\'s favorite hero is %s.\n", Kid1, Hero1);
printf("%s\'s favorite hero is %s.\n", Kid2, Hero2);
printf("%s\'s favorite hero is %s.\n", Kid3, Hero3);
return 0;
}
The problem is with char Hero1 = "Batman":
When you use a double-quoted string of characters in your code, the compiler replaces it with a pointer to the beginning of the memory space in which the string will reside during runtime.
So by char Hero1 = "Batman", you are actually attempting to assign a memory address (which typically consists of 32 or 64 bits of data, depending on your system) into a character variable (which typically stores 8 bits of data).
In order to fix the problem, you need to change it to either one of the following options:
char Hero1[] = "Batman"
char* Hero1 = "Batman"
FYI, in both cases above, the string "Batman" will reside in a read-only memory section during runtime.
However, there is a notable difference between these two cases:
Using char Hero1[], the "Batman" string will be copied into the stack every time the function is called. The Hero1 array will start at that address, and you will be able to change the contents of that array at a later point within the function.
Using char* Hero1, the "Batman" string will not be copied into the stack every time the function is called. The Hero1 variable will be pointing to the original address of the string, hence you will not will be able to change the contents of that string at any point within the function.
When the executable image is generated from your code, the string is placed in the code-section, which is one of several memory-sections within the program. The compiler then replaces the so-called "string assignment" with a so-called "integer assignment".
For example, char* x = "abc" is changed into char* x = (char*)0x82004000 before being compiled into object code, where 0x82004000 is the (constant) address of the string in the program's memory space.
When you do sizeof("abc"), the executable image will not even contain the "abc" string, since there is no "runtime" operation performed on this string.
There is no object code generated for sizeof - the compiler computes this value during compilation, and immediately replaces it with a constant.
You can look into the (intermediate) map file that is usually generated, and see that the input string of that sizeof operation does not appear anywhere.
char Hero1 = "Batman";
should be
char Hero1[] = "Batman";
A couple times you have some issues:
#include <stdio.h>
#include <string.h>
main()
{
char Kid1[12];
// Kid1 can hold an 11-character name
// Kid2 will be 7 characters (Maddie plus null 0)
char Kid2[] = "Maddie";
// Kid3 is also 7 characters, but specifically defined
char Kid3[7] = "Andrew";
// Hero1 will be 7 characters (adding null 0!)
char *Hero1 = "Batman"; //needs to be a pointer
// Hero2 will have extra room just in case
char *Hero2 = "Spiderman"; //needs to be a pointer
char Hero3[25]
Kid1[0] = 'K'; //Kid1 is being defined character-by-character
Kid1[1] = 'a'; //Not efficient, but it does work
Kid1[2] = 't';
Kid1[3] = 'i';
Kid1[4] = 'e';
Kid1[5] = '\0'; // Never forget the null 0 so C knows when the
// string ends
strcpy(Hero3, "The Incredible Hulk");
printf("%s\'s favorite hero is %s.\n", Kid1, Hero1);
printf("%s\'s favorite hero is %s.\n", Kid2, Hero2);
printf("%s\'s favorite hero is %s.\n", Kid3, Hero3);
return 0;
}
You should define all of your vars at the top of the function, its a good C practice.
Other than that, I flagged the issues (and corrected them) with comments.
Solution:
This error you get because String data type is not in C
programming you can print string by using array or char pointer like
1.Array:
#include<stdio.h>
int main(){
char a[]={'a','b','c','d','f','\0'};
printf("%s",a);
return 0;
}
Click here to check the output of solution array
2.char pointer:
#include<stdio.h>
int main(){
char* a="abcd";
printf("%s",a);
return 0;
}
Click here to check the output of solution char pointer

What is the size of a double pointer string?

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

Char x[50] and Char x[100] Output

I'm not used to C as I'm primarily a Java guy, with some knowledge of C++, so forgive me if this is a trivial question. I could not seem to find an answer while searching online.
I'm initializing a char array...
char tcp[50];
So that I can concatenate a const char and a char. In examples I saw an easy way to do this was by creating that empty char array and then using...
strcat(x,y);
To stick them together.
Problem is, printing out the blank char array when it is set to "50" gives me a result of:
X??|?
When I change it to...
char tcp[100];
And print it, its blank. Why is this?
The array contents are undefined, assuming it is a local (automatic) array.
Use:
char tcp[50] = "";
Or:
char tcp[50] = {0};
Or:
char tcp[50];
tcp[0] = 0;
Or:
char tcp[50];
memset(tcp, 0, sizeof(tcp));
As you like.
Always null terminate you char arrays before doing anything:
tcp[0] = '\0';
C happily allocates the space for the array you declare, but it does not set its content to 0.
Therefore, the content of the array you're printing is random (or rather depending in the previous contents of the memory)
When creating an array, the compiler puts it somewhere in memory but does not initialize it, so whatever is in that memory when the program is started will be the initial "string".
Terminate the string manually after you created the array, either by making the whole array "zeroed" out, or just put zero as the first character:
char tcp[50] = { '\0' };
Or
char tcp[50];
/* ... */
tcp[0] = '\0';
The difference here is, you're essentially working with two empty arrays trying to merge them in the memory space of one (not sure if that makes sense for you).
First of all, in C you have to terminate strings with \0. That's something not exposed or visible in Java. Also you essentially used two undefined strings (as there's no value set).
#include <stdio.h>
#include <string.h>
char target[256];
const char source_a[] = "Hello";
const char source_b[] = "World!";
int void(main)
{
target[0] = '\0'; // this essentially empties the string as we set the first entry to be the end. Depending on your language version of C, you might as well write "char target[256] = {'\0'};" above.
strcat(target, source_a); // append the first string/char array
strcat(target, " "); // append a const string literal
strcat(target, source_b); // append the second string
printf("%s\n", target);
return 0;
}
Important: Using strcat() can be unsave, as there's no length check performed, and other than Java, these "strings" have a fixed length (the one you set when defining the variables). If there's no length given, but you copy a string on initialization, that length is taken (e.g. char test[] = "Hello!"; will be 7 chars long (due to terminating \0)).
If you'd like a more Java like approach on strings, use C++ and the std::string class, that performs a lot more similar to Java's strings.

Resources