am trying to write a function to parser command line arguments into a vector. The problem is i can't seem to eliminate the use of a global array of pointers as the vector.
The code is:
/** parse command line arguments into a global vector */
char vects[8][32] = {0};
int str_tokenizer(const char str[], char delim)
{
extern char vects[8][32];
int i,num_delim=0, num_vects;
int str_len=strlen(str);
for(i=0;i<str_len;i++)
{
if(str[i]==delim)
num_delim++;
}
num_vects=num_delim+1;
int x=0;
vects[num_vects][32];
for(i=0;i<num_vects;i++)
{
//printf("%i", i);
int y=0;
while(str[x]!=delim && str[x]!='\0')
{
//printf("%c", str[x]);
vects[i][y++]=str[x++];
}
vects[i][y]='\0';
x++;
}
return (num_vects);
}
Any help will be appreciated
I think you're doing too much in one function. You should separate the tasks of parsing (just isolating the substrings of the original string, ie. discovering the starting and ending indices) on the one hand, and adding strings to a list on the other hand. To replace a 2D array, you can use a linked-list. But the parsing code should not have to worry about this, just scan for the next delimiter. Subtract the ending position from the starting position to get the length, and call an append_string_to_list() function, passing the full source string and the starting index and length.
By the way, you refer to this array
char vects[8][32] = {0};
as a "global array of pointers". It is not an array of pointers. It is an array of arrays of characters. To be sure, if you use a slice of the array, by not specifying the second index, then it will work as if it were a pointer -- and it will decay to a pointer in a function-call -- but a real array of pointers would look like this:
char *vects[8];
Related
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);
}
following situation:
I have a list of words. For example:"Hello","Hey","Help","Shark".
I want to save those in the array apcWord (word-array.. more specific, a pointer-array).
And I have a pointer pcBeg to the beginning string "He"
I have to solve this with this function prototype:
void search (char *apcString[], char *pcBeg)
How can I filter the array of words and just printf the words which start with "He".
I'am totally confused.. I tried some things with strstr() but no result. The problem is the list of words and filter all words with this "He" beginning. if I just have one word and just want to know if its beginning with "He" or not its no problem.
I hope I made my problem as clear as possible.
Thanks for your Help!
I have a list of words ? probabaly you want to declare array of pointer variable of char type. for e.g
char *apcWord[4] = {"Hello","Hey","Help","Shark"};
And I have a pointer pcBeg to the beginning string "He" ? as you said declare a char pointer. for e.g
char *pcBeg = "Hi";
I have to solve this with this function prototype: ? You should learn how to pass array of pointers to function. If you are passing array of char pointers to a function, you need to catch with double pointer of char type. Here is the sample code
void search (char **apcString, char *pcBeg,int ele) {
/* logic */
}
How can I filter the array of words and just printf the words which start with "He". ? use strncmp() instead of strstr(). open man 3 strncmp and third argument of strncmp() is useful for your part of question quoting words which start with "He". Here is the sample code
void search (char **apcString, char *pcBeg,int ele) {
int count = 0;
for(int row = 0 ;row < ele ;row++) {
if(strncmp(apcString[row],pcBeg,strlen(pcBeg)) == 0) {
count++;
}
}
printf(" count of %s is : %d \n",pcBeg,count);
}
Finally how to call search() from main() function
int main(void) {
char *apcWord[5] = {"HelloHi","HiHey","Help","Hi","Shark"};
int ele = sizeof(apcWord)/sizeof(apcWord[0]);
char *pcBeg = "Hi";
search(apcWord,pcBeg,ele);/* 3rd arg :- pass the no of element in the array of pointer */
return 0;
}
I hope I made my problem as clear as possible. ? No you didn't. We don't know what code you tried, its advisable to put the code whatever you tried into your question so that you can get more help.
And finally suggest you to read some good C book about array, pointers etc concept & learn how to debug a small code using gdb https://ericlippert.com/2014/03/05/how-to-debug-small-programs/ .
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have this code:
char** SplitToWords(char* str);
int main()
{
char** wordarr;
char str[] = "This is a sentence";
wordarr = SplitToWords(str);
return 0;
}
After the main comes the function implementation.
I am not sure the following does what I want it to do (i.e. receive an array of strings from a function):
wordarr = SplitToWords(str);
I somehow managed to convince the compiler that it's ok, but I assume it just does something else.
If it does, how do I find out the length of the array (the number of strings in it).
Thanks
I'll try to quickly visit all aspects you might not yet fully understand:
A string in C is described as a contiguous sequence of chars, ending with a char of value 0 (as a literal: '\0'). It is not a first class object, therefore hasn't its own type. So what you use to hold a string is an array of char. Therefore, taking your question by the word, "receive an array of strings from a function" is not possible.
An array is a contiguous sequence of objects of the same type. In C, the identifier of an array doesn't have a value itself; when it's evaluated, it decays as a pointer to the array's first element instead. This is especially important when passing arrays to functions or returning them from functions -- you can't actually pass the array, you always pass a pointer
e.g. you could write:
char x[] = "foo"; // initialize a char array from a string literal
char *xp = x; // here, x evaluates as a pointer to the first element of the array
You already use pointer types for your function's argument and return value, I just think it's quite important to understand what happens entirely.
You write char** SplitToWords(char* str); and ask whether this returns an "array of strings" -- well, sort of, as you should understand after reading 1. and 2. -- What it does is returning a pointer to char *. This pointer could be a pointer to the first element of an array. So in this case, it would return a pointer to an array of char * pointers. Each of these pointers could itself be a pointer to an array of chars, therefore point to a string. But what's very important is to understand you never return an array, you always return a pointer to it. It's so important because:
You might get the idea to do something like this:
char** SplitToWords(char* str)
{
char *words[16];
// code to fill `words` with pointers to the actual words
return words; // WRONG!
}
Here, because you're not returning the array words but a pointer to it (see point 2), you return a pointer to an object that no longer exists. words is in the scope of your function and has automatic storage duration, that means it only lives as long as the execution is inside of the function. One solution would be to declare words with the static storage class specifier. This way, it lives for the entire execution time of the program. But be aware that this also means there's only a single instance ever, it's always the same object. This will be a major headache for threaded programs, for example. The other way around is to dynamically allocate words using malloc(). But then, the caller of the function must free() it later.
As for your second question, how to let the caller know the number of words -- it's in the comments already, but just for completeness, a typical approach to solve this is to append another entry that is a NULL pointer. So the caller can iterate over the pointers until it finds NULL.
Regarding your comment, of course you can create the array outside the function and pass a pointer to the function, so the function only fills it. This is a common idiom in C (e.g. think about fgets(), which takes a pointer to the char array that's filled with a string by the function).
Functions working this way will need an additional size_t parameter, so they know the size of the array they should fill through the pointer, otherwise you'd have the risk of buffer overflows (this is why gets() was finally removed from the C standard). If you decide that the caller provides the storage, your function should have this prototype:
// returns the number of words found, up to `nwords`
size_t SplitToTwords(char **words, size_t nwords, char *str);
It should be called e.g. like this:
char *words[16];
size_t nwords = SplitToWords(words, 16, "the quick brown fox"); // returns 4
Remember that the strings holding the words themselves need storage as well. You can either manipulate the bytes in str to insert a '\0' after each word, overwriting the first whitespace character (this is what strtok() does) or you can copy the words to new strings, but then you would have to malloc() each of them again and the caller has to free() them later.
Yes, you could solve it by using a function with return value char **. However, there's no way to find out how many words there are afterwards.
You can solve this by allocating one more element for the return pointer and set it to NULL. Then you can get the number of words with this code:
wordarr = SplitToWords(str);
char **ptr=wordarr;
int noWords=0;
while(!*(ptr+noWords))
noWords++;
But if you want to return multiple data in C, you either need to define a return struct or using return arguments. In this case, it could look like this for the first option:
typedef struct wordList {
char **wordarr;
int noWords;
}
wordList SplitToWords(char* str);
And the second:
char** SplitToWords(char* str, int *noWords);
or
void SplitToWords(char* str, char*** wordarr, int *noWords);
Note that there's three *. That's because we want it to be a pointer to char **
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSTRINGS 5000
int main(int argc, char *argv[]) {
char *stringTable[MAXSTRINGS];
char sentence[] = "This is a sentence";
char *token = NULL;
int i = 0;
while ((token = strtok(token == NULL ? sentence : NULL, " ")) != NULL)
{
printf("%s\n\r", token);
stringTable[i] = (char *)malloc(strlen(token) + 1); //have no "plain" C compiler - VS C++ used so cast needed :)
strcpy(stringTable[i++], token);
}
stringTable[i] = NULL; // if you need to iterate through later
printf("%d tokens found\n\r", i);
for (int y = 0; y < i; y++)
free(stringTable[y]);
}
What Parameters should I give this function? I think it needs a string array but I don't know the exact syntax.
void write_file(char *result[], int len)
{
..
}
char result[10];
write_file(&(result[0]), 10);
or
char result[10];
write_file(result, 10);
which is the same, as array identifier is simply the address of its first element
Infact it does not need string array. In C, you can not send array to a function and also you can not return an array from a function. Solution? You can send "the" array's starting point and it's length. Then the receiver side can understand "the" array. About your question, you must send start position of the array as first argument and length of the array as the second argument.
char *result[] means an array of pointers to char. However the question is what is the meaning of the parameter len?
Normally with a function named something like write_file() the function would write a character string to an output and the len parameter would be the number of characters to write out.
To use this function as the function looks would mean something like:
char *myStrings[] = {
"string 0",
"string 1"
};
write_file (myStrings, 0); // passing zero as len as unsure what it is.
Or something like:
char *myStrings[20]; // array of pointers to chars
int iLoop;
for (iLoop = 0; iLoop < 20; iLoop++) {
myStrings[iLoop] = malloc(1000); // allocate a large buffer for each string
read_string (myStrings[iLoop], 1000); // some made up function to read a string
}
write_file (myStrings, 20);
What I suspect is that the function should actually be void write_file(char *result, int len) or it should be void write_file(char result[], int len) so that rather than accepting an array of pointers to char arrays (how strings are normally used in C) it should be accepting a pointer to a char array.
So the idea of write_file() would be to write a single string to a file rather than several strings.
I am under the impression that on each run, in my Strings array, I am storing at pos a new str since I am declaring it everytime, instead, on the 2nd run if addstr become hello, and on the first run It was hi, the first run hi also becomes hello. I just want a different char array on each run in Strings so later on each position I have a different strings. The requirements is that I can not use malloc, realloc, calloc. I really thought that on the 2nd iteration of the first for loop I am creating on a char str independent of the previous one. Please help me.
int pos = 0;
for(i=0; i<4; i++)
{
if(file [i]=='a')
{
char str[5];
int b=0;
for(b; b<3; bi++)
{
str[b]=file[b];
}
Strings[pos]=str;
pos++;
}
}
When you do this:
Strings[pos]=str;
It merely sets that array element to the buffer pointed to by 'str'. It does not copy the string. The 'str' buffer never changes, so your entire array ends up pointing to the same buffer.
Rather, at that line you need to copy the string. If you can't use malloc, then your Strings array needs to have buffers at each array element (aka 2 dimensional array). Maybe declare it something like:
char Strings[5][5];
Then instead of using your strcpy to copy to 'str', copy the string to 'Strings[pos]';