I have the following code in which I'm reading lines from a file and want to save them using a character pointer array. As I'm using one buffer inside my file read loop all my pointers in the character array end up pointing towards the last line read from file as the last line is the one that is currently held in the buffer when the loop terminates. How can I store them such that each pointer in the character array points to different char arrays in the order they were read.
int num_clients_to_start = 0;
char *token1, *token2, *str;
FILE* fp;
char bufr[256];
char testchar[255] = {};
char *start_client[10];
while(fgets(bufr, 256, fp) != NULL){
if(bufr[0] == '#'|| bufr[0] == '\n')
continue;
str = bufr;
token2 = ""; /* initializing an empty token 2 */
for(str = bufr; ;str = NULL){
token1 = strtok(str, " ");
if(strcmp(token2, "client_name") == 0){
sprintf(testchar,"%s", token1);
start_client[num_clients_to_start] = testchar;
num_clients_to_start++;
}
token2 = token1;
if(str == NULL){
break;
}
}//end of for loop
}//end of while loop
printf("client1 = %s client2 = %s client3 = %s",start_client[0],start_client[1],start_client[2]);
My input file is the following:
client_name abc
client_name def
client_name xyz
And print statement outputs:
client1 = xyz
client2 = xyz
client3 = xyz
Note that start_client[0], [1], [2] are all pointers to the last string (readed by fgets)
Use strdup in order to allocate them:
start_client[num_clients_to_start] = strdup(testchar);
As strdup can be an external identifier, use a prototype
#include <string.h>
char *strdup(const char *s);
And don't forget to free() at the end
You assign the same pointer to all entries in the start_client array. The array testchar will get different contents, but the pointer to it will always be the same. You might want to make start_client an array of arrays of char, and copy the string instead.
Like
char start_client[10][256];
And
strcpy(start_client[num_clients_to_start++], token1);
Related
I have a string like:
my age is 22\r\n\r\n and I live in Rostock
and some other strings like:
I like to swim\r\n\r\n .Yesterday I competed with my 2 friends
Now I want to split a string by \r\n\r\n and have it associated with buffer. Here is what I am trying to do:
char buffer[500];
strcpy(buffer, "my age is 22\r\n\r\n and I live in Rostock");
char *p = buffer;
if((p = strchr(p,"\r\n\r\n"))) {
p[strcspn(p,"tock")] = 0; // trying to slice until the end
}
printf("%s", p);
This gives me a warning as I try to compile saying warning: passing argument 2 of ‘strchr’ makes integer from pointer without a cast I could not understand what this meant.
Also what is good way to split this into 2 char buffers?
strchr expects a mere char and not a string for its second parameter. So you can only pass it a single character.
In C a char is a single character and strings are null terminated char arrays.
What you want to do is probably:
char buffer[500] = "my age is 22\r\n\r\n and I live in Rostock"; // directly initialize the char array
const char sep[] = "\r\n\r\n";
char * p = strstr(buffer, sep); // search the separator
if (p) {
*p = '\0'; // null terminate the first part
p += strlen(sep); // make p point to the start of the second part
printf("%s - %s\n", buffer, p);
}
If you really need to purge the initial part from buffer and have it start at the second part, you could do:
for (char *dest = buffer; p<buffer+sizeof(buffer)-1;) { // do not go past end of array
*dest++ = *p++;
if (*p == '\0') break; // stop on first null
}
I want to save part of a string into a new char array while including the period. For example, the string is:
My name is John. I have 1 dog.
I want to copy each char up to and including the first period, so the new char array will contain:
My name is John.
The code I have written below copies only "My name is John" but omits the period.
ptrBeg and ptrEnd point to the char at the beginning and end, respectively, of the portion I want to copy. My intention was to copy ptrBeg into array newBuf through a pointer to newBuf and then increment both ptrBeg and the pointer to the array until ptrBeg and ptrEnd point to the same char, which should always be a period.
At this point, the text of the string should be copied, so I increment the pointer to char array once more and copy the period to the new space using
++ptrnewBuf;
*ptrnewBuf = *ptrEnd";
Finally, I print the contents of newBuf.
Here's the total code:
int main()
{
char buf[] = "My name is John. I have 1 dog.";
char * ptrBuf;
char * ptrBeg;
char * ptrEnd;
ptrBeg = buf;
ptrBuf = ptrBeg;
while (*ptrBuf != '.'){
ptrBuf++;
}
ptrEnd = ptrBuf;
char newBuf[100];
char * ptrnewBuf = newBuf;
while(*ptrBeg != *ptrEnd){
*ptrnewBuf = *ptrBeg;
ptrnewBuf++;
ptrBeg++;
}
++ptrnewBuf;
*ptrnewBuf = *ptrEnd;
printf("%s", newBuf);
}
How would I modify this code to include a period?
You are on the right track, but you may be making things a bit more complicated than needed and overlooking a few critical checks. The key to iterating by pointers or using pointer arithmetic is to always validate and protect your array or memory bounds during each iteration or arithmetic operation.
Another tip is to always map out your pointer positions on a piece of paper before coding everything up so you have a clear picture of what your iteration limits and any adjustments need to be. (you don't have to use full long strings and many boxes, just use a representation of what needs to be done with a handful of characters) In your case where you wish to copy the substing up through the first '.', something simple like the following will do, e.g.
+---+---+---+---+---+---+
| A | . | | B | . |\0 |
+---+---+---+---+---+---+
^ ^
| pointer (when *p == '.')
buf
So to copy "A." from buf to a new buffer you can't simply iterate while (*p != '.') or you will not copy '.'. By drawing it out, you can clearly see you need to also copy the character when p == '.', e.g.
+---+---+---+---+---+---+
| A | . | | B | . |\0 |
+---+---+---+---+---+---+
^ ^
| |-->| pointer (p + 1)
buf
Now regardless of the actual length of the string before '.', you now know you need p + 1 as the final address to include the last character in the copy.
You also know how many characters your new buffer can store. Say the size of new is MAXC characters (maximum number of characters). So you can store a string of at most MAXC-1 characters (plus the nul-character). When you are filling new you need to always validate you are within MAXC-1 characters.
You also need to insure you new string is nul-terminated (or it isn't a string, it's simply an array of characters). One effective way to insure nul-termination is by initializing all characters in new to 0 when it is declared, e.g.
char new[MAXC] = "";
which initializes the 1st character to 0 (e.g. '\0' empty-string) and all remaining characters 0 by default. Now if you fill no more than MAXC-1 characters, you are guaranteed the array will be a nul-terminated string.
Putting it altogether, you could do something like the following:
#include <stdio.h>
#define MAXC 128 /* if you need a constant, #define one (or more) */
int main (void) {
char buf[] = "My name is John. I have 1 dog.",
*p = buf, /* pointer to buf */
new[MAXC] = "", /* buffer for substring */
*n = new; /* pointer to new */
size_t ndx = 0; /* index for new */
/* loop copying each char until new full, '.' copied, or end of buf */
for (; ndx + 1 < MAXC && *p; p++, n++, ndx++) {
*n = *p; /* copy char from buf to new */
if (*n == '.') /* if char was '.' break */
break;
}
printf ("buf: %s\nnew: %s\n", buf, new);
return 0;
}
(note: ndx is incremented as part of the for loop to track the number of characters copied with the pointers)
Example Use/Output
$ ./bin/str_cpy_substr
buf: My name is John. I have 1 dog.
new: My name is John.
If you do not have the luxury of initializing the string to insure nul-termination, you can always affirmatively nul-terminate after your copy is done. For example, you could add the following after the for loop exit to insure an array of unknown initialization is properly terminated:
*++n = 0; /* nul-terminate (if not already done by initialization) and
* note ++n applied before * due to C operator precedence.
*/
Look things over and let me know if you have further questions.
Just breaking it out into a helper function that "extracts" the first sentence from a line. Just copies the characters over one at a time until either an end of string condition is hit on the source, the period is found, or a max length of the destination buffer is encountered.
void ExtractFirstSentence(const char* line, char* dst, int size)
{
int count = 0;
char c ='\0';
if ((line == NULL) || (dst == NULL) || (size <= 0))
{
return;
}
while ((*line) && ((count+1) < size) && (c != '.'))
{
c = *line++;
*dst++ = c;
count++;
}
*dst = '\0';
}
int main()
{
char buf[] = "My name is John. I have 1 dog.";
char newBuf[100];
ExtractFirstSentence(buf, newBuf, 100);
printf("%s", newBuf);
}
if you want something a bit easier without dealing with all those pointers, try :
int main()
{
char buf[] = "My name is John. I have 1 dog.";
int i = 0;
int j = 0;
while(buf[i] != '.' && buf[i] != '\0') {
i++;
}
char newbuf[i+1];
while (j <= i) {
newbuf[j] = buf[j];
j++;
}
newbuf[j] = '\0';
printf("%s\n",newbuf);
return 0;
}
though the i+1 when making newbuf and the newbuff[j] = '\0' im not 100% certain need to be that way. my thoughts are the i+1 is needed to make room for the \0 ending which is then added after the while loop copying buf to newbuf. but i could be mistaken.
You can use strtok() to split string. Just type man strtok, You will see:
Program source
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
char *str1, *str2, *token, *subtoken;
char *saveptr1, *saveptr2;
int j;
if (argc != 4) {
fprintf(stderr, "Usage: %s string delim subdelim\n",
argv[0]);
exit(EXIT_FAILURE);
}
for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
token = strtok_r(str1, argv[2], &saveptr1);
if (token == NULL)
break;
printf("%d: %s\n", j, token);
for (str2 = token; ; str2 = NULL) {
subtoken = strtok_r(str2, argv[3], &saveptr2);
if (subtoken == NULL)
break;
printf(" --> %s\n", subtoken);
}
}
exit(EXIT_SUCCESS);
}
An example of the output produced by this program is the following:
$ ./a.out 'a/bbb///cc;xxx:yyy:' ':;' '/'
1: a/bbb///cc
--> a
--> bbb
--> cc
2: xxx
--> xxx
3: yyy
--> yyy
we get input from user (command line) and store it in in char* input[].
This input will look like this, when the user inputs all required information:
input[]: add John Smith (male) <relation> Emma Stone (female).
Then we want to copy it to new_input[] with 8 positions (for example John would be on the position 1). In our first example this will look like the same:
new_input []: add John Smith (male) <relation> Emma Stone (female)
But there are possibilities that we don't get all the information from the user. Especially it is most likely we don't get the last name. So, during the copy we need to add some ‘if-statements’ to check if the user puts e.g. Smith or not. If not – we want write ‘NULL’ at the positions 2 and 6. The array looks then like:
if input []: add John (male) <relation> Emma (female)
new_input []: add John NULL (male) <relation> Emma NULL (female)
Unfortunately, we have difficulties with copying array of string pointers to a new array.
We tried memcpy(), new_input[i] = input[i] (in a for-loop).
EDIT: here is code and i also edit example above, (new_input with NULL on position 2 and 6 if last names are missing)
`int main(int argc, char* argv[])
{
char* copy_input = NULL;
int len_max = 256;
int error = 1;
char* input = (char*) malloc(len_max* sizeof(char));
if (argc == 1)
{
while(1)
{
printf("cmd> ");
char read[len_max];
input = fgets(read, len_max, stdin);
int len = strlen(read);`
if(read[len-1] == '\n')
{
read[len-1] = '\0';
}
copy_input = input;``
error = handleUserInput (copy_input);
}`
in handle user command, we split string by space and check first string, if it is " add " , go to function addCommand (in)
`
int handleUserInput(char* input) // takes char input from main and compares type of command
{
printf("input: %s\n",input );
char* in[8];
int i = 0;
char* temp;
char delimiter[] = " ";
temp = strtok(input, delimiter);
in[i++] = temp;
while( temp != NULL)
{
temp = strtok(NULL, delimiter);
in[i++] = temp;
// printf("%s\n", temp);
}
if(!strcmp(in[0], "add"))
{
addCommand(in);
}`
In function add command, we want to do copy input to new_input as i described above...
`int addCommand(char* input[]) //
{
char* new_input[];
`
If you are using the new_input[i] = input[i]
You're gonna assign the pointeur of input[i] to the new_input[i]
then thing is that it would not be a copy it's just a copy of the string personnal adress.
So if u want to make a real copy with it's "own memory" u need to first allocate a new string and then copy the content of the last string in the new.
(man strdup)
To copy an array of string pointer you will probably do a basic method wich mean to first allocate your double pointeur (char **array)
to receive your new content.
and then loop to copy all the content with the method that i've show you just before
I am trying to read the file and get file content and store it in 2 element array [0]: is for content [1]: is for NULL value. This code is working correctly when just I want to print it but I want to use as an array:
char ch;
FILE *file;
file = fopen("input.txt","r");
int allocated_size = 10;
int used_size = 0;
char c, *input, *tmp_input;
// allocate our buffer
input = (char*)malloc(allocated_size);
if (input == NULL) {
printf("Memory allocation error");
return 1;
}
while ((c = fgetc(file)) != EOF){
// make sure there's an empty one at the end to avoid
// having to do this check after the loop
if (used_size == allocated_size-1) {
allocated_size *= 2;
tmp_input = (char*)realloc(input, allocated_size);
if (tmp_input == NULL) {
free (input);
printf("Memory allocation error");
return 1;
}
input = tmp_input;
}
input[used_size++] = c;
}
// we are sure that there's a spot for last one
// because of if (used_size == allocated_size-1)
input[used_size] = '\0';
printf("\nEntered string in the file: %s\n", input);
But how can I use "input" like an array:
char *input[] = {"This is string value from file!", NULL};
For this case I can get access to the text in this way: input[0]
So in order to achieve this
char *input[] = {"This is string value from file!", NULL};
If I am understanding correctly from your write-up then declare input as this
char *input[2];
And every time you perform any operation on your string pointer e.g. malloc and re-alloc etc. use input[0] . This way array's first record will contain your text.
The reason behind this, the string in first record means you need array of char pointers.
How can I create an array of unique strings without knowing how many strings there are until I process the input file? There can be as many as 2 million strings, max length of 50.
My program is something like this. This works for 51 items then overwrites other data. I don't know how to add an element to the array, if possible.
main() {
char *DB_NAMES[51]; // i thought this gave me ptrs to chunks of 51
// but it's 51 pointers!
char *word;
while not eof {
...function to read big string
...function to separate big sting into words
...
processWord(ctr, DB_NAMES, word);
...
}
}
processWord(int ndx, char *array1[], char *word){
...function to find if word already exists...
//if word is new, store in array
array1[ndx]= (char *)malloc(sizeof(51)); // isn't this giving me a char[51]?
strcpy(array1[ndx],word);
...
}
You can first get the number of words in your file using the below logic and when you get the number of words in the file you can initialize the array size with the word count.
#include<stdio.h>
#define FILE_READ "file.txt"
int main()
{
FILE * filp;
int count = 1;
char c;
filp = fopen(FILE_READ, "r");
if(filp == NULL)
printf("file not found\n");
while((c = fgetc(filp)) != EOF) {
if(c == ' ')
count++;
}
printf("worrds = %d\n", count);
return 0;
}
Regards,
yanivx
Better not use a fixed string length; save memory space.
char **DB_NAMES = 0; // pointer to first char * ("string") in array; initially 0
Pass pointer by reference so that it can be altered. Moreover, you'll want the new ctr value in case a new word has been stored.
ctr = processWord(ctr, &DB_NAMES, word);
Change function processWord accordingly.
int processWord(int ndx, char ***array1a, char *word)
{ char **array1 = *array1a;
...function to find if word already exists...
// if word is new, store in array
{
array1 = realloc(array1, (ndx+1)*sizeof*array1); // one more string
if (!array1) exit(1); // out of memory
array1[ndx++] = strdup(word); // store word's copy
*array1a = array1; // return new array
}
return ndx; // return count
}