Declaring an array of character pointers (arg passing) - c

This is something that should be easy to answer, but is more difficult for me to find a particular right answer on Google or in K&R. I could totally be overlooking this, too, and if so please set me straight!
The pertinent code is below:
int main(){
char tokens[100][100];
char *str = "This is my string";
tokenize(str, tokens);
for(int i = 0; i < 100; i++){
printf("%s is a token\n", tokens[i]);
}
}
void tokenize(char *str, char tokens[][]){
int i,j; //and other such declarations
//do stuff with string and tokens, putting
//chars into the token array like so:
tokens[i][j] = <A CHAR>
}
So I realize that I can't have char tokens[][] in my tokenize function, but if I put in char **tokens instead, I get a compiler warning. Also, when I try to put a char into my char array with tokens[i][j] = <A CHAR>, I segfault.
Where am I going wrong? (And in how many ways... and how can I fix it?)
Thanks so much!

You would need to specify the size of the second dimension of the array:
#define SIZE 100
void tokenize(char *str, char tokens[][SIZE]);
This way, the compiler knows that when you say tokens[2][5] that it needs to do something like:
Find the address of tokens
Move 2 * SIZE bytes past the start
Move 5 more bytes past that address
???
Profit!
As it stands, without the second dimension specified, if you said tokens[2][5] how would it know where to go?

You're close. Arrays and pointers aren't the same thing, even though it sometimes seems like they are. You can either make your two-dimensional array out of pointers:
char **tokens = malloc(100 * sizeof(char *));
for (i = 0; i < 100; i++)
tokens[i] = malloc(100);
And then use:
void tokenize(char *str, char **tokens)
or you can specify the size of the array in your tokenize() function:
void tokenize(char *str, char tokens[][100])

Related

Initializing array of pointers to char from a 2d char array

I have a function
int executeCommand(char args[][TOKENSIZE]){
char *argv[] = {args[0], args[1]}; // This works
char *argv[] = {args}; // This doesn't
}
The args variable will not be of fixed length so I can't use the first line as it is. I don't want to use malloc or free due to some reasons. Is there any way of initializing this argv array from args without hard coding the number of entries.
The function needs to know the size somehow or it is mission impossible. One possible way is to use pointers to VLA:
int executeCommand(size_t n, char args[n][TOKENSIZE]){
char* argv[n];
for(size_t i=0; i<n; i++)
{
argv[i] = args[i];
}
}
As for you why you can't simply use args instead of copying the array addresses, I have no idea.
A complete hard-copy of the data would look like
char argv[n][TOKENSIZE];
memcpy(argv, args, sizeof(char[n][TOKENSIZE]));

Concatenate char array and int array and store in string array

I would like to concatenate char array and the int array and store them in another char array. How could I do that?
Here is the code so far
char letter[100];
int number[100], i;
char * letterNum[100];
for (i = 0; i < 100; i++){
letterNum[i] = strcat(letter[i], number[i]);
}
expected output should be
a1 b1 ...
The strcat() function concatenates strings not chars, you need sprintf()
sprintf(letterNum[i], "%c%d", letter[i], number[i]);
and also, letterNum in your case is an array of pointers, it should be an array of arrays, like
char letterNum[100][3];
and then, you can use snprintf() instead of sprintf() to prevent buffer overflow
if (snprintf(letterNum[i], 3, "%c%d", letter[i], number[i]) > 2)
youHaveToDoSomethin_An_Error_Occurred();
I guess Mr. Iharob already answered your question, but just to elaborate a bit more,
Let's see the man page of strcat(). It says,
char *strcat(char *dest, const char *src);
which means it expects both the arguments to be pointer to strings. Now, as we know, a pointer to int array cannot be considered a string, we cannot use strcat() directly in your case.
So, what you have to do is,
Take another buffer
Copy both the contents of the char array and int array elements for particular index one after another in lexicographical format, so that the final result is the concatenation of both.
Now, you have sprintf()/ snprintf() to help you out in this case. It prints the formatted o/p to the supplied string.
A pseudo-code
char letter[100]; //populating value, not shown
int number[100]; //populating value, not shown
int i = 0;
char letterNum[100][32];
for (i = 0; i < 100; i++){
if ( sprintf(letterNum[i], "%c%d", letter[i], number[i]) != 2)
printf("Error in %d iteration\n", (i+1));
}
Thank you very much for your help!
I guess, I need to try an error and test it out myself... the explaination was clear and helpful... plus given codes for me to eeasily understand...
Your kind help is greatly aappreciated.. Thank you once again

Sorting an array of strings in C

I have an assignment I've been working on for a few hours now, and I can't seem to get it quite right. The assignment is to take a random number of names (from stdin), sort them, and then output them in alphabetical order. I can't find any sites online that handle this kind of sorting specifically, and have had no luck trying to implement qsort() into my code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int stringcmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return strcmp(*ia, *ib);
}
void main(int argc, char *argv[])
{
char *input[] = {" "};
char temp[20][20];
int i = 0;
int num = 0;
int place = 0;
int stringlen = sizeof(temp) / sizeof(char);
printf("How many names would you like to enter? ");
scanf("%d", &num);
while (place < num)
{
printf("Please input a name(first only): ");
scanf("%s", input[place]);
printf("The name you entered is: ");
printf("%s\n", input[place]);
place++;
}
//qsort(temp, stringlen, sizeof(char *), stringcmp); <-- just an idea I was messing with
qsort(input, stringlen, sizeof(char *), stringcmp);
printf("Names:\n");
for(i=0; i<place; i++)
printf("%s\n", input[i]);
system("PAUSE");
return(EXIT_SUCCESS);
}
The main problem is, when I go to output my code, I cannot use the char *input variable because of how its declared. The temp[] will display, but will not be sorted by qsort because it is not declared as a pointer. Any ideas?
You can't declare your input array like that. Since you know how many the user requires, you can dynamically allocate the array:
char **input = malloc(num * sizeof(char*));
Likewise, when you read your strings in, they need somewhere to go. Simply passing an uninitialized pointer to scanf is not okay. I suggest you define the maximum length of a name and have a temporary buffer for reading it:
const size_t MAX_NAME = 50;
char name[MAX_NAME];
...
for( i = 0; i < num; i++ )
{
printf("Please input a name(first only): ");
scanf("%s", name);
input[i] = strdup(name);
}
[Note this does not prevent the user from overflowing the 'name' buffer. I used scanf for illustrative purposes only]
You seem to be passing the wrong array length to qsort. Try this:
qsort(input, num, sizeof(char *), stringcmp);
When you are finished, you need to release memory for all the names and the array.
for( i = 0; i < num; i++ ) free(input[i]);
free(input);
could you explain
the ** declarations throughout the code? I'm not sure what they're
used for, although I know the function for stringcmp is a widely used
algorithm, I have no idea how it works; I'm thrown off by the double
de-reference markers.
Yep, in the case where I used it, I am telling C that to get a single character, I have to dereference a pointer twice. When you index a pointer, it's dereferencing. So I allocated an array by requesting a block of memory containing num * sizeof(char*) bytes. Because I assigned that pointer to a char**, the compiler knows that I am pointing to a chunk of memory that contains char* values.
If I ask for input[0] (this is the same as *input) it should look at the very start of that memory and pull out enough bytes to form a char*. When I ask for input[1], it skips past those bytes and pulls out the next bunch of bytes that form a char*. Etc... Likewise, when I index a char*, I am pulling out single characters.
In your stringcmp function, you have the following situation. You passed a void* pointer to qsort so it doesn't actually know the size of the data values stored in your array. That's why you have to pass both the array length AND the size of a single element. So qsort just blindly rips through this arbitrary-length array of arbitrary-sized values and fires off memory addresses that ought to contain your data for comparison. Because qsort doesn't know anything else about your array elements except where they are located, it just uses void*.
But YOU know that those pointers are going to be the memory addresses of two of your array elements, and that your array elements are char*. So you need the address of a char* (hence you cast the pointers to char**). Now you need to dereference these pointers when you call strcmp() because that function requires a char* (ie a value that points directly to the memory containing your string characters). That is why you use the * in strcmp(*ia, *ib).
One quick way to fix your program is to declare input as an array of pointers, like this:
char *input[20];
When you read names in, use tmp[place] for your buffer, and store the pointer into input, like this:
scanf("%19s", tmp[place]);
input[place] = tmp[place];
Now sorting the input should work fine.
This has a limitation of being limited to 20 lines of 20 characters max. If you learned about malloc in the class, you should be able to fix that by allocating your strings and the string array dynamically.

Mistake with storing strings in char pointer array

I know this question might sound quite silly, but I somehow found myself stuck and need help. I have a char* variable char* address="/a/asdasd/c/sdfsdf/adsd"; and I declared an array of char pointer char* store[5]; . I'm trying to divide the content in the variable address by tracing the slash(/) and trying to store each part in the char pointer variable store by doing the following
char* store[5];
char* address="/a/asdasd/c/sdfsdf/adsd";
int k=0;
int j=0;
char* b=NULL;
for(int i=0;i<5;i++)
{
if(b==0)
{
b=strchr(address,'/');
}
else
{
b=strchr(b,'/');
}
j=b-address;
strncpy(store[i],address+k,j-k);
k=j;
}
But I see that in the code strncpy(store[i],address+k,j-k) there's an error. The compiler doesn't seem to understand that store[i] is a char pointer, it rather thinks it is a char. Could you see how I can solve the problem?
Thanks for all the help. I've solved it. Solution code is as below:
char* address="/a/asdasd/c/sdfsdf/adsd/asfsd";
char store[5][100];
char* b=NULL;
int k=0;
int j=0;
for(int i=0;i<5;i++)
{
if(b==0)
{
b=strchr(address+1,'/');
}
else
{
b=strchr(b+1,'/');
}
j=strlen(address)-strlen(b);
strncpy(store[i],address+k+1,j-k-1);
store[i][j-k-1]='\0';
printf("%s\n",store[i],j-k);
k=j;
}
char *store[5]
This is just an array of char pointers. To store strings in each element of this array, you need malloc memory and assign it to the respective pointer.
For Ex, you can change your code to
store[i] = malloc ((j-k)+ 1); // +1 is for the null terminator. Pls check return value of malloc also.
strncpy(store[i],address+k,j-k);
If you want to copy a pointer, you shouldn't be calling strncpy(), since that copies characters.
You want:
store[i] = address + (j - k);
assuming address + (j - k) is the desired starting point for the part.
If you don't want to have a copy of the string tokens, if you like only to retain the pointers, then just store the address in store[i] as #unwind pointed out. Or else, you could explore strtok () also. only think is that you need to have separate array to keep each length of the string according to your code. Hope this helps.

passing a char array by reference in C

Hi I really can't get my head around this. I'm basically trying to return a char array from a function by passing the output array in as a parameter. Here is what I have so far:
The function:
int GetComputerName(char *name, char *ip_address){
*name = "testing";
return 0;
}
And calling it:
char comp_name[50];
GetComputerName(&comp_name, serverIP);
printf("\n\n name: %s\n\n", comp_name);
I have tried switching and swapping the * and & to see what will work and have read up on pointers and stuff yet what I think should be happening an what actually does happen is two very different things and now I think I have confused myself more than when I started!! lol
Can someone please help me out and explain what the correct way of doing this is?!
Thanks in advance =)
This line:
*name = "testing";
is invalid, as you assign the pointer to "testing" into a char pointed by name. You need to copy the data into the buffer. It should be:
int GetComputerName(char *name, char *ip_address){
strcpy(name,"testing");
return 0;
}
or even better (to avoid overflows):
int GetComputerName(char *name, size_t buff_len, char *ip_address){
strncpy(name,"testing", buff_len);
name[buff_len - 1] = '\0';
return 0;
}
And call it:
GetComputerName(comp_name, sizeof(comp_name), serverIP);

Resources