I am processing an input string, which consists of a process name, followed by an arbitrary amount of arguments.
I need the process name , along with all of the arguments, in one string.
I thought I could use strcat in a loop, so that it cycles through all of the args and each time appends the arg to the string, but I am having problems with getting a string that in empty to begin the loop.
Can anyone help me out with some basic code?
Thanks.
EDIT:
I'm posting my code for clarity. Mike's post is closest to what I have now:
char * temp;
strcpy(temp,"");
for (i = 4; i < argc-1; i++) // last arg is null, so we need argc-1
{
strcat(temp,argv[i]);
strcat(temp," ");
}
ignore the 4 in my for loop for the moment (magic number, i know.)
I am getting a segfault with this code. Is it because of my string assignment? I assume that is the case and hence I asked the question of how i could combine the strings.
Let's say your input strings are in an array of char pointers, suggestively called argv, of length argc.
We first need to determine how much space is needed for the output:
int length = 0;
for (int i = 0; i < argc; ++i)
length += strlen(argv[i]);
Then we allocate it, adding an extra char for the '\0' terminator:
char *output = (char*)malloc(length + 1);
Finally, the concatenation:
char *dest = output;
for (int i = 0; i < argc; ++i) {
char *src = argv[i];
while (*src)
*dest++ = *src++;
}
*dest = '\0';
Note that I don't use strcat here. Reason is that this sets us up for a Schlemiel the Painter's algorithm: for each iteration, the entire output string would be scanned to find its end, resulting in quadratic running time.
Don't forget to free the output string when you're done:
free(output);
I'm a bit tired so I may be overlooking something here. A better solution, using standard library functions, is welcome. It would be convenient if strcat returned a pointer to the terminator byte in dest, but alas.
You want an empty C string? Is this what you are looking for: char p[] = "";?
UPDATE
After you posted some code it is clear that you have forgotten to allocate the buffer temp. Simply run around the arguments first, counting up the length required (using strlen), and then allocate temp. Don't forget space for the zero terminator!
You could provide the "arbitrary amount of arguments" as one argument, ie an array/list, then do this pseudocode:
str = "";
i = 0;
while i < length of input
{
str = strcat ( str , input[i]);
i++;
}
#include<stdio.h>
#include<stdarg.h>
int main(int argc, char** argv) {
// the main parameters are the same situation you described
// calling this program with main.exe asdf 123 fdsa, the program prints out: asdf123fdsa
int lengths[argc];
int sum =0;
int i;
for(i=1; i<argc; i++) { // starting with 1 because first arg is program-path
int len = strlen(argv[i]);
lengths[i] = len;
sum+=len;
}
char* all = malloc(sum+1);
char* writer = all;
for(i=1; i<argc; i++) {
memcpy(writer, argv[i], lengths[i]);
writer+=lengths[i];
}
*writer = '\0';
printf("%s\n", all);
system("pause");
return 0;
}
A string in C is represented by an array of characters that is terminated by an "null" character, '\0' which has the value 0. This lets all string functions know where the end of a string is. Here's an exploration of different ways to declare an empty string, and what they mean.
The usual way of getting an empty string would be
char* emptyString = "";
However, emptyString now points to a string literal, which cannot be modified. If you then want to concatenate to an empty string in your loop, you have to declare it as an array when you initialize.
char buffer[] = "";
This gives you an array of size one. I.e. buffer[0] is 0. But you want an array to concatenate to- it has to be large enough to accomodate the strings. So if you have a string buffer of certain size, you can initialize it to be empty like so:
char buffer[256] = "";
The string at buffer is now "an empty string". What it contains, is buffer[0] is 0 and the rest of the entries of the buffer might be garbage, but those will be filled once you concatenate your other strings.
Unfortunately, the problem with C, is you can never have an "infinite" string, where you are safe to keep concatenating to, you have to know it's definite size from the start. If your array of arguments are also strings, you can find their length using strlen. This gives you the length of a string, without the null character. Once you know the lengths of all your sub-strings, you will now know how long your final buffer will be.
int totalSize; // assume this holds the size of your final concatenated string
// Allocate enough memory for the string. the +1 is for the null terminator
char* buffer = malloc(sizeof(char) * (totalSize + 1));
buffer[0] = 0; // The string is now seen as empty.
After this, you are free to concatenate your strings using strcat.
Related
I am currently learning C and am trying to fill an array of strings with a loop as a simple exercise. I am just trying to fill all 4 elements with the word "Hello". When I print my array out I get output like this:
messages[0] = HelloHelloHelloHello
messages[1] = HelloHelloHello
messages[2] = HelloHello
messages[3] = Hello
For an odd reason, the first 3 elements have the word hello repeating mulitple times. I do not understand why this is happening.
Here is my code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char messages[4][5];
for(int i = 0; i < 4; i++){
//&messages[i] = (char *)malloc(5);
strcpy(messages[i],"Hello");
}
for(int i = 0; i < 4; i++){
printf("messages[%d] = %s\n", i, messages[i]);
}
return 0;
}
I also tried looking up way to do this, and I found something about using malloc, but I just kept getting compiler errors.
You have not allocated memory for the null terminator.
char messages[4][5]; should be char messages[4][6];
Since there is no null terminator. printf prints the character until null terminator is found.And also the last strcpy copies the \0 beyond the memory allocated by you. This is undefined behavior.
As mentioned in the other replies, the problem is in the statement
strcpy(messages[i], "Hello");
The array messages is declared as an array of four arrays of length five but the size of the string "Hello" is actually six characters; the terminating null character is an invisible part of the string. If you print the value of sizeof "Hello" you will get the value six.
If you just need an array of strings which you don't intend to change, you can declare your array as
const char *messages[] = {"Hello", "Hello", "Hello", "Hello"};
Here the length of the array is inferred from the initializer.
It is also a good idea to not hard code the length of the array in more then one place. In my own code I always use the array length macro
#define LEN(array) ((int) (sizeof (array) / sizeof (array)[0]))
With this you can write
for (int i = 0; i < LEN(messages); i++) {
...
}
If you then want to change the length of messages you only need to change the declaration.
Strings in C are terminated by a zero byte - that is, a byte containing zero. Thus, to hold a five character string you need to reserve six characters for it - five for the data and one for the terminator. If you increase the size of the second dimension of your array of characters to six instead of five it will work as you expected:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char messages[4][6];
for(int i = 0; i < 4; i++){
//&messages[i] = (char *)malloc(5);
strcpy(messages[i],"Hello");
}
for(int i = 0; i < 4; i++){
printf("messages[%d] = %s\n", i, messages[i]);
}
return 0;
}
Let's say that I have the following character array. I need to know if there is a way to get the length of the second string in the array. I know I could use strlen, but this gives me the length of the first string.
#include <stdio.h>
int main()
{
char greeting[20]={'P','H','O','N','E','\0','6','0','1','7','1','2','1','2','1','6','\0'};
int count;
count=strlen(greeting); // this returns the length of first string which is 5
}
A valid string in C is null terminated
Having 2 null characters in the char array might cause lot of issues especially while using inbuilt functions.
If you really want to do this
strlen(greeting + 1 + strlen(greeting));
strlen() works on a null terminated strings and if you pass just greeting to it then the length will be calculated till the first null is encountered and length will be returned so now we need length from the character after first null so you should calculate as shown above.
Simple, generic, readable way:
size_t s_length [SUBSTRINGS];
const char* strp = greeting;
for(size_t i=0; i<SUBSTRINGS; i++)
{
s_length[i] = strlen(strp);
strp += s_length[i] + 1; // +1 to skip null termination
}
I'm using the code below to add some "0" chars into my string, but it seems there is a problem and the program will crash. Everything seems logic but I do not know where is the problem?
#include <stdlib.h>
#include <string.h>
int main()
{
char *Ten; int i=0; Ten = malloc(12);
Ten="1";
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
return 0;
}
You declare Ten as a pointer to a string literal. However, you cannot rely on being able to modify a string literal, and thus the program crashes.
To fix this, you can declare Ten as an array instead:
int main()
{
char Ten[12]="1"; int i=0;
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
return 0;
}
Note that you need 12 bytes; 11 for the characters and one for the terminating NUL character.
Ten is a string literal and you cannot modify it. Try with array instead
char Ten[12] = "1";
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
notice that I created an array of 12 characters, because there should be room for a termination '\0'.
You actually don't need strcat here, it's just do this
char Ten = malloc(12);
if (Ten != NULL)
{
Ten[0] = '1';
for (i = 1 ; i < 11 ; i++)
Ten[i] = '0';
Ten[11] = '\0';
/* Use Ten here, for example printf it. */
printf("%s",Ten);
/* You should release memory. */
free(Ten);
}
or
char Ten = malloc(12);
if (Ten != NULL)
{
Ten[0] = '1';
memset(Ten + 1, '0', 10);
Ten[11] = '\0';
/* Use Ten here, for example printf it. */
printf("%s",Ten);
/* You should release memory. */
free(Ten);
}
To quote from strcat manual on linux:
The strcat() function appends the src string to the dest string,
overwriting the terminating null byte ('\0') at the end of dest, and
then adds a terminating null byte. The strings may not overlap, and
the dest string must have enough space for the result. If dest is not
large enough, program behavior is unpredictable; buffer overruns are
a favorite avenue for attacking secure programs.
Your Ten array is only long enough to store original literal. You need to preallocate memory as long as final desired string.
String literals might be stored in read only section of memory. Any attempt to modify such a literal causes undefined behavior.
To concatenate two strings, the destination must have enough space allocated for the characters to be added and space for '\0'. Change the declaration of Ten to
char Ten[12] = "1";
and it will work.
I want to copy X to Y words of a string to the out char * array.
unsigned char * string = "HELLO WORLD!!!" // length 14
unsigned char out[9];
size_t length = 9;
for(i=0 ;i < length ;++i)
{
out[i] = string[i+3];
}
printf("%s = string\n%s = out\n", string, out);
When looking at the output of out, why is there gibberish after a certain point of my string? I see the string of out as LO WORLD!# . Why are there weird characters appearing after the content I copied, isn't out supposed to be a an array of 9? I expected the output to be
LO WORLD!
In C you need to terminate your string with a 0x00 value so a string of length 9 needs ten bytes to store it with the last set to 0. Otherwise your print statements run off into random data.
unsigned char * string = "HELLO WORLD!!!" // length 14
unsigned char out[10];
size_t length = 9;
for(i=0 ;i < length ;++i)
{
out[i] = string[i+3];
}
out[length] = 0x00;
printf("%s = string\n%s = out\n", string, out);
A minor point, but string literals have type char* (or const char* in C++), not unsigned char* -- these might be the same in your implementation, but they don't need to be.
Furthermore, this is not true:
unsigned char * string = "HELLO WORLD!!!" // length 14
The string actually occupies 15 bytes -- there is an extra, hidden '\0' at the end, called a nul byte, which marks the end of the string. These nul terminators are very important, because if they're not present, then many C library functions which manipulate strings will keep going until they hit a byte with a value equal to '\0' -- and so can end up reading or trampling over bits of memory they shouldn't do. This is called a buffer overrun, and is a classic bug (and exploitable security problem) in C programmes.
In your example, you haven't included this nul terminator in your copied string, so printf() just keeps going until it finds one, hence the gibberish you're seeing. In general, it's a good idea only to use C library functions to manipulate C strings if possible, as these are careful to add the terminator for you. In this case, strncpy from string.h does exactly what you're after.
A 9 character string needs 10 bytes because it must be null ( 0 ) terminated. Try this:
unsigned char out[10]; // make this 10
size_t length = 9;
for(i=0 ;i < length ;++i)
{
out[i] = string[i+3];
}
out[i] = 0; // add this to terminate the string
A better approach would be just the line:
strncpy(out, string+3, 9);
C strings must be null terminated. You only created an array large enough for 8 characters + the null terminator, but you never added the terminator.
So, you need to allocate the length plus 1 and add the terminator.
// initializes all elements to 0
char out[10] = {0};
// alternatively, add it at the end.
out[9] = '\0';
Think of it this way; you're passed a char* which represents a string. How do you know how long it is? How can you read it? Well, in C, a sentinel value is added to the end. This is the null terminator. It is how strings are read in C, and passing around unterminated strings to functions which expect C strings results in undefined behavior.
And then... just use strncpy to copy strings.
If you want to have copy 9 characters from your string, you'll need to have an array of 10 to do that. It is because a C string needs to have '\0' as null terminated character. So your code should be rewritten like this:
unsigned char * string = "HELLO WORLD!!!" // length 14
unsigned char out[10];
size_t length = 9;
for(i=0 ;i < length ;++i)
{
out[i] = string[i+3];
}
out[9] = 0;
printf("%s = string\n%s = out\n", string, out);
I'm coding a program that takes some files as parameters and prints all lines reversed. The problem is that I get unexpected results:
If I apply it to a file containing the following lines
one
two
three
four
I get the expected result, but if the file contains
september
november
december
It returns
rebmetpes
rebmevons
rebmeceds
And I don't understand why it adds a "s" at the end
Here is my code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void reverse(char *word);
int main(int argc, char *argv[], char*envp[]) {
/* No arguments */
if (argc == 1) {
return (0);
}
FILE *fp;
int i;
for (i = 1; i < argc; i++) {
fp = fopen(argv[i],"r"); // read mode
if( fp == NULL )
{
fprintf(stderr, "Error, no file");
}
else
{
char line [2048];
/*read line and reverse it. the function reverse it prints it*/
while ( fgets(line, sizeof line, fp) != NULL )
reverse(line);
}
fclose(fp);
}
return (0);
}
void reverse(char *word)
{
char *aux;
aux = word;
/* Store the length of the word passed as parameter */
int longitud;
longitud = (int) strlen(aux);
/* Allocate memory enough ??? */
char *res = malloc( longitud * sizeof(char) );
int i;
/in this loop i copy the string reversed into a new one
for (i = 0; i < longitud-1; i++)
{
res[i] = word[longitud - 2 - i];
}
fprintf(stdout, "%s\n", res);
free(res);
}
(NOTE: some code has been deleted for clarity but it should compile)
You forget to terminate your string with \0 character. In reversing the string \0 becomes your first character of reversed string. First allocate memory for one more character than you allocated
char *res = malloc( longitud * sizeof(char) + 1);
And the try this
for (i = 0; i < longitud-1; i++)
{
res[i] = word[longitud - 2 - i];
}
res[i] = '\0'; // Terminating string with '\0'
I think I know the problem, and it's a bit of a weird issue.
Strings in C are zero terminated. This means that the string "Hi!" in memory is actually represented as 'H','i','!','\0'. The way strlen etc then know the length of the string is by counting the number of characters, starting from the first character, before the zero terminator. Similarly, when printing a string, fprintf will print all the characters until it hits the zero terminator.
The problem is, your reverse function never bothers to set the zero terminator at the end, which it needs to since you're copying characters into the buffer character by character. This means it runs off the end of your allocated res buffer, and into undefined memory, which just happened to be zero when you hit it (malloc makes no promises of the contents of the buffer you allocate, just that it's big enough). You should get different behaviour on Windows, since I believe that in debug mode, malloc initialises all buffers to 0xcccccccc.
So, what's happening is you copy september, reversed, into res. This works as you see, because it just so happens that there's a zero at the end.
You then free res, then malloc it again. Again, by chance (and because of some smartness in malloc) you get the same buffer back, which already contains "rebmetpes". You then put "november" in, reversed, which is slightly shorter, hence your buffer now contains "rebmevons".
So, the fix? Allocate another character too, this will hold your zero terminator (char *res = malloc( longitud * sizeof(char) + 1);). After you reverse the string, set the zero terminator at the end of the string (res[longitud] = '\0';).
there are two errors there, the first one is that you need one char more allocated (all chars for the string + 1 for the terminator)
char *res = malloc( (longitud+1) * sizeof(char) );
The second one is that you have to terminate the string:
res[longitud]='\0';
You can terminate the string before entering in the loop because you know already the size of the destination string.
Note that using calloc instead of malloc you will not need to terminate the string as the memory gets alreay zero-initialised
Thanks, it solved my problem. I read something about the "\0" in strings but wasn't very clear, which is now after reading all the answers (all are pretty good). Thank you all for the help.