I have an array of strings: {"foo", "bar", "baz"} and I want to convert it into an array array of string: {{"foo", "bar", "baz"}}, (part of a bigger project).
My program will use args as an array of strings, so the input is: ./a.out foo bar baz.
With 1 and 3 arguments it works nice, but with 2 arguments it gives me segmentation fault.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ***args2cmd(int argc, char **args){
//Create array of array of strings
char ***arr = malloc(sizeof(char ***));
int tami = 0;
int tamj = 0;
//Arry of strings
arr[tami] = malloc(sizeof(char **));
//String
arr[tami][tamj] = malloc(sizeof(char *));
for(int i=0; i<argc; i++){
tamj++;
arr = realloc(arr, tamj * sizeof(**arr));
arr[tami][tamj-1] = args[i];
}
return arr;
}
int main(int argc, char **args) {
char ***arr = args2cmd(argc, args);
for(int i=0; arr[i]; i++){
for(int j=0; arr[i][j]; j++){
printf("%s ", arr[i][j]);
}
printf("\n");
}
return 0;
}
Bellow is a little code demonstration of how you could use an array of void pointers to accomplish your task. Code is fully commented with all relevant explanations. Compile with gcc -o astr astr.c.
Call with ./astr hello world from command line, for example.
/* astr.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
/* #n is the number of string you passed the function */
char **build_array(int n, ...)
{
/* no error checking...
* +1 because we terminate the array with a NULL
*/
char **s = malloc((n + 1) * sizeof(*s));
va_list ap;
int i;
va_start(ap, n);
for(i = 0; i < n; i++)
s[i] = va_arg(ap, char *);
va_end(ap);
/* terminate the array with a NULL */
s[i] = NULL;
return s;
}
int main(int argc, char **argv)
{
/* array of strings is just an array of pointers...
*
* Since you can play around with void points _by the standard_,
* we can just make an array of voids to hold whatever pointers we
* want, IFF we keep track of the types for the conversions.
*
* Say we do:
*
* astr[0] = argv; // this is type (char **)
*
* and them we do
*
* float **foo = astr[0]; // VALID SYNTAX, but WRONG SEMANTIC
*
* The above is valid syntax since we can convert to and from
* void pointers, but we stored (char**) in astr[0], not
* (float**), and this will blow up in your face.
*/
void **astr;
/* alloc space for the array of strings.
* no error cheking!
*/
astr = malloc(3 * sizeof(*astr));
/* the first element is the command line.
* You could make a function to copy #argv into a new array
*/
astr[0] = argv;
/* just a helper function to build some more arrays */
for(int i = 1; i < 3; i++)
astr[i] = build_array(3, "hello", "world", "!!!");
for(int i = 0; i < 3; i++) {
char **s = astr[i];
printf("Array #%d at addr %p\n", i, s);
/* This assumption is dangerous! You should always KNOW
* the size of your arrays
*/
for(int j = 0; s[j]; j++)
printf("s[%d] = %s\n", j, s[j]);
}
return 0;
}
After your comment:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ***args2cmd(int argc, char **args)
{
//Create array of array of strings
// FIRST malloc()
char ***arr = malloc(sizeof(char ***));
int tami = 0;
int tamj = 0;
/* arr => 1 slot for 1 array
*/
//Arry of strings
// SECOND malloc
arr[tami] = malloc((argc + 1) * sizeof(char **));
/* arr[tami] = malloc(sizeof(char**)) gives us just
* arr[0] => 1 slot, which doesn't make sense.
*
* So we change it, because WE KNOW the size of the array! It's
* going to hold argc + 1 strings. Why the +1? Because you use the
* trick of stoping loops based on a NULL element.
*
*
* Keep in mind that #tami is bound the the amount of space pointed
* to by arr! So, that's the first malloc() you did.
*
*/
//String
//arr[tami][tamj] = malloc(sizeof(char *));
/* arr[0][0] = 1 slot
*
* If this is a string, why only one slot?
* You need more space for strings, ie:
* arr[tami][tamj] = malloc(strlen(something))
*
* So we comment this out, since it doesn't make any sense here.
*/
int i; /* so we can use it later for the NULL */
for (i = 0; i < argc; i++) {
/* strdup() will alloc space and copy the string you give it
* to this new region, then it will return your region. It's
* similar to doing:
* char *s1 = "hello":
* char *s2 = malloc(strlen(s1));
* return strcpy(s2, s1);
*/
arr[tami][i] = strdup(args[i]);
}
/* you assume the arrays end with NULL, so you
* have to put it here
*/
arr[tami][i] = NULL;
return arr;
}
int main(int argc, char **args)
{
char ***arr = args2cmd(argc, args);
for (int i = 0; arr[i]; i++) {
for (int j = 0; arr[i][j]; j++) {
printf("%s ", arr[i][j]);
}
printf("\n");
}
return 0;
}
Related
Im just curious if there is anyway of directly converting a char array to a char* array such as:
char charArray[5]={'h','e','l','l','o'};
'Converted' to:
char *pointerArray[5]={"h","e","l","l","o"};
How about this?
#include <stdio.h>
#include <stdlib.h>
char **convert_array(char *arr_in, size_t arr_in_sz)
{
char **arr_out = (char **)malloc(arr_in_sz * sizeof(char *));
for (size_t i = 0; i < arr_in_sz; ++i) {
arr_out[i] = (char *)malloc(2);
arr_out[i][0] = arr_in[i];
arr_out[i][1] = '\0';
}
return arr_out;
}
void free_array(char **arr, size_t arr_sz)
{
for (size_t i = 0; i < arr_sz; ++i)
free(arr[i]);
free(arr);
}
int main()
{
char array_char[] = {'h', 'i'};
char **array_str = convert_array(array_char, sizeof(array_char));
for (size_t i = 0; i < sizeof(array_char); ++i)
printf("%s\n", array_str[i]);
free_array(array_str, sizeof(array_char));
}
You only need a place to store the string literals. You need twice as much memory as for the charArray - to store letters and zero terminating characters, one zero for each letter - twice as much memory. Then initialize pointerarray to point to every second character inside memory. Like so:
#include <stdio.h>
int main() {
char chararray[5]={'h','e','l','l','o'};
char memory[sizeof(chararray) * 2];
for (unsigned i = 0; i < sizeof(chararray); ++i) {
memory[i * 2] = chararray[i];
memory[i * 2 + 1] = '\0';
}
char *pointerarray[5];
for (unsigned i = 0; i < sizeof(chararray); ++i) {
// this loop could me merged with above loop
pointerarray[i] = &memory[i * 2];
}
for (unsigned i = 0; i < 5; ++i) {
printf("%s\n", pointerarray[i]);
}
}
The first one is one dimensional array and secon one is two dimensional. So if you just use pointer like that :
char *pointerArray it means you have an array but you can not assign like in the first example.
I need help with the following program:
Print all sorted strings from the input array of strings.
Assume that strings are sorted if characters are in lexicographic order (also assume that the only characters in strings are letters).
Example:
INPUT:
n=2
1. string: stack
2. string: exchange
OUTPUT:
No sorted strings
I am having a problem with accessing some variables in the following program:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 30
char** read(int *pn);
int isSorted(char *str);
char** sortedArr(char **str,int pn);
char** read(int *pn)
{
do
{
printf("n = ");
scanf("%d",pn);
}
while(*pn < 1);
char **arr;
arr=(char **)malloc(*pn * sizeof(char *));
int i;
for(i=0; i<*pn;i++)
arr[i]=(char *)malloc(MAX+1);
for(i=0; i<*pn; i++)
{
printf("%d. word: ",i+1);
scanf("%s",arr[i]);
}
return arr;
}
int isSorted(char *str)
{
int i,j;
for(i=0; i<strlen(str)-1;i++)
for(j=i+1; j<strlen(str); j++)
if(strcmp(str+i,str+j) > 0)
return 1;
return 0;
}
char** sortedArr(char **str,int pn)
{
char **sortArr;
sortArr=(char **)malloc(pn * sizeof(char *));
int i;
for(i=0; i<pn; i++)
{
if(isSorted(sortArr[i]))
sortArr[i]=(char *)malloc(MAX+1);
}
for(i=0; i<pn; i++)
{
if(isSorted(sortArr[i]))
printf("%d. word: %s",sortArr+i);
}
return sortArr;
}
int main()
{
char **arr;
char **sortArr;
int pn;
arr=read(&pn);
sortArr=sortedArr(arr,pn);
int i;
for(i=0; i<pn; i++)
free(arr[i]);
free(arr);
return 0;
}
The problem is how to access the variable pn in function sortedArr()?
Your program has several issues, I'll try to address the most part of them.
Let's start from the isSorted function, if your goal is to check if a word has all the character sorted, you don't need to use strcmp or a nested loop. All what you need is something like this:
// check if all the character in the string are sorted
int isSorted( char *str )
{
int i, length = strlen(str) - 1;
for ( i=0; i < length; i++ )
if ( str[i] > str[i+1] )
return 0;
return 1;
}
I'll separate the printing function from the input one and copy ones, so to have:
void print( char **str, int n )
{
int i;
for ( i = 0; i < n; i++ ) {
printf("word %d: %s\n", i + 1, str[i]);
}
}
There are several methods to read some words from stdin and some are presented in other answers. I'll use this, but you should check all the pointers returned from malloc:
char** read(int *pn)
{
char buffer[BUFSIZE];
printf("Please, enter number of words: ");
while ( *pn < 1 && fgets(buffer, BUFSIZE, stdin) ) {
sscanf(buffer, "%d", pn);
}
int i = 0, length;
printf("\nPlease, enter the words: \n");
char **arr = malloc(*pn * sizeof(char *));
while ( i < *pn ) {
// read words one line at a time
if ( !fgets(buffer, BUFSIZE, stdin) )
break;
length = strlen(buffer);
// ignore empty lines
if ( length < 2 )
continue;
arr[i] = malloc(length);
memcpy(arr[i],buffer,length);
// add the null terminator
arr[i][length - 1] = '\0';
++i;
}
*pn = i;
return arr;
}
Then, I'm not really sure if you want only to print the words that are "sorted" or you actually need to copy them (and print later). I'll show you the latter:
// return an array of string containing only the sorted ones
char** sortedArr( char **str, int n, int *m)
{
char **sortArr = NULL;
char *sorted = calloc(n,1);
int i;
*m = 0;
// first find (and count) the sorted strings
for ( i = 0; i < n; i++ ) {
if ( isSorted(str[i]) ) {
// maybe you need only to print str[i] now...
sorted[i] = 1;
++(*m);
}
}
// then copy the sorted. I'm not sure if you need this
int j = 0, length = 0;
if ( *m ) {
sortArr = malloc(*m * sizeof(char *));
for ( i = 0; i < n; i++ ) {
if ( !sorted[i] )
continue;
length = strlen(str[i]) + 1;
sortArr[j] = malloc(length);
memcpy(sortArr[j],str[i],length);
}
}
free(sorted);
return sortArr;
}
Finally the main function (and the one to free allocated memory):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BUFSIZE 128
char** read( int *pn );
int isSorted( char *str );
char** sortedArr( char **str, int n, int *m );
void print( char **str, int n );
void freeArr( char **str, int n );
void freeArr( char **str, int n )
{
if ( !str ) return;
int i;
for ( i = 0; i < n; i++ ) {
free(str[i]);
}
free(str);
}
int main()
{
char **arr = NULL;
char **sortArr = NULL;
int n = 0, m = 0;
arr = read(&n);
print(arr, n);
printf("\nSorted: \n");
sortArr = sortedArr(arr,n,&m);
print(sortArr, m);
freeArr(sortArr, m);
freeArr(arr, n);
return 0;
}
Hope it helped. Tell me if there is something wrong or I have misunderstood your task.
Change the sortedArr function, so that it takes pn as an argument:
char** sortedArr(char **str, int pn)...
Then, in your main(), change the sortArr=sortedArr(arr) to sortArr=sortedArr(arr, pn), to pass the value to the function. Then you can use the pn value inside the sortedArr function.
One head-scratcher is:
for(i=0; i<*pn;i++)
arr[i]=(char *)malloc(strlen(arr+i)+1);
for(i=0; i<*pn; i++)
{
printf("%d. word: ",i+1);
scanf("%s",arr[i]);
}
You should combine both because you cannot allocate properly until you know the length of word. Allocating some strlen(arr+i)+1 for who knows what is at arr+i is meaningless (and unless arr+i just happens to be a nul-terminated string, undefined behavior). When you are taking input, you can/should use a temprory buffer to hold the input until you can validate it is what you want it to be. At minimum, test the return to scanf to insure you actually had a sucessful conversion to the type of input you are expecting. For instance:
for (i = 0; i < *pn; i++)
{
char buf[64] = ""; /* however long is sufficient for word */
printf ("%d. word: ",i+1);
if (scanf ("%63[^\n']%*c",buf) == 1)
arr[i] = strdup (buf); /* allocates/copies buf for arr[i] */
else {
fprintf (stderr, "error: invalid input for word[%d].\n", i);
}
}
(note: you have similar allocation issues in sortedArr)
For your sort, you need to pass pn as a parameter to sortedArr so you at least know how many strings you are dealing with. Rather than looping and attempting to compare adjacent elements, why not have your sortedArr function simply call qsort and sort the array you create in read. If you want to preserve both the original and sorted arrays, then have sortedArr call memcpy and create a copy of arr and then call qsort on the copy. All you need to do is create a string comparison compare function for qsort to compare arr or the copy, e.g.:
/* comparison function for qsort (char **) */
int cmp_str (const void *a, const void *b)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference
note: to reverse sort order, swap a and b, below */
return strcmp (* (char * const *) a, * (char * const *) b);
}
Which you can then use to sort your arr (or copy) with
qsort (arr, pn, sizeof *arr, cmp_str);
Much less error-prone then a one-off loop and index attempt. Give it a try and let me know if you have questions.
I am trying to pass a array of pointers to string to a function where I need to set the values. In the passing function I do not know the number of strings I will get, the called function is calling some other function which returns list of strings.
Sample code below:
int main() {
char** list;
create(list);
}
int create(char **array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
for (i = 0; i < 2; i++) {
len = strlen(str[i]);
printf("%d\n", len);
*(array + i) = (char*) malloc(len * sizeof(char*));
strcpy(*(array + i), str[i]);
i++;
}
return 1;
}
This gives me segmentation fault.
What wrong am I doing here. Please help.
Thanks
EDIT
Updated code from below comments:
int main() {
char** list;
create(list);
int i = 0;
for (i = 0; i < 2; i++) {
printf("%s\n", list[i]); // segmentation fault
}
}
int create(char **array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
array = malloc(2 * sizeof(char*));
for (i = 0; i < 2; i++) {
len = strlen(str[i]);
printf("%d\n", len);
*(array + i) = (char*) malloc(len * sizeof(char));
strcpy(*(array + i), str[i]);
printf("%s\n", array[i]); // this prints
}
return 1;
}
Now getting segmentation fault in main while printing the list.
Actual code where I am reading the strings
int i;
for ( i=0; i<reply->elements; i++ )
{
printf( "Result: %d---%s\n", i,reply->element[i]->str );
*array[i] = (char*)malloc(strlen(reply->element[i]->str));
printf("***");
strcpy(array[i],reply->element[i]->str);
printf( "Array[%d]: %s\n", i,array[i] );
}
You correctly alloc memory for the individual strings, but fail to alloc some for the array itself.
You should use:
int main() {
char* list[8] = {0}; /* initialize pointers to NULL */
create(list);
/* free allocated memory - free(NULL) is legal and is a noop */
for (i=0; i<sizeof(list)/sizeof(list[0]); i++) free(list[i]);
return 0; /* never return random value from main */
}
And you should remove the i++ at the end of the loop in function create because it leads to a double increment.
Alternatively you could alloc the array itself in the function create:
int create(char ***array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
*array = malloc(1 + sizeof(str)/sizeof(str[0]));
for (i = 0; i < 2; i++) {
len = strlen(str[i]) + 1;
printf("%d\n", len);
(*array)[i] = malloc(len * sizeof(char*));
strcpy((*array)[i], str[i]);
}
(*array)[i] = NULL;
return i;
}
int main() {
char** list;
create(&list);
}
In above code, the length of the array is the return value from create, and the last element of list is a NULL (in the same logic as argc/argv).
You need to allocate some space for list or undefined behavior occurs:
char* list[2];
You increment i twice; therefore, remove the i++ from the bottom of the for loop.
Minor notes:
refer to string literals as const char*
use array[i] instead of *(array + i)
don't cast the result of malloc
malloc allocates too much space as you allocate len char*s, even though you need just chars. Also, as #CoolGuy noted, you need one extra byte for the null byte. Replace the allocation with
array[i] = malloc(len * sizeof(char) + sizeof(char));
or
array[i] = malloc(len + 1);
call free after malloc
you assign 0 twice to i; remove the initialization
You allocate two arrays (char*) to store the strings "hello" and "dear" but does not allocate the array (char**) containing those two string array.
I would suggest you to change declaration of function create to this -
int create(char ***array);
And call it like this -
create(&list);
In function create allocate memory like this -
*array = malloc(2 * sizeof(char*));
for (i = 0; i < 2; i++)
{
len = strlen(str[i]);
printf("%d\n", len);
(*array)[i] =malloc(len * sizeof(char*)+1);
strcpy((*array)[i], str[i]);
}
And do the printing as you do in main.
Note - free memory that you allocate.
And you should declare len as type size_t -> size_t len;
and print it with %zu specifier in printf .
See working code here -https://ideone.com/GX2k9T
I'm trying to use scanf to fill an array of char pointers to store the input as a string. The variable T is used to build an array of size T dynamically. Then T amount of strings are entered and displayed however when I fill in the array for example if T = 2 the first line could dog and the second line cat, it prints out "cdog" and "cat". So the first letter of the first string then the all of the 2nd string. I'm not sure where my mistake is in using char*. Any help would be appreciated.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main()
{
int T;
int i;
scanf("%d",&T);
char *new_array = (char*)malloc(T * sizeof(char));
for (i = 0; i < T; ++i)
{
scanf("%s", new_array+i);
}
for (i = 0; i < T; i++)
{
printf("%s\n", new_array+i);
}
}
Always check the return value of scanf().
You are not allocating space for pointers, but for bytes, which is the main problem, you need
char **new_array = malloc(T * sizeof(char *));
/* ^ ^ */
/* allocate pointer to poitners sizeof(pointer) */
if (new_array == NULL)
handleThisErrorAndDoNotTryToWriteTo_new_array();
you will also need space for each string so
new_array[i] = malloc(1 + lengthOfTheString);
if (new_array[i] == NULL)
handleThisErrorAndDoNotTryToWriteTo_new_array_i();
right before scanf(), and instead of scanf("%s", new_array + i) do this
scanf("%s", new_array[i]);
If you enable compiler warnings, the compiler should warn you that you are passing incompatible types to printf().
It would also be good, to use a length modifier for scanf() to prevent buffer overflow, and don't forget to call free() when you no longer need the pointers.
In your code, new_array is of type char *, which is not what you want. You have to change your definition to
char *new_array[T] = malloc(T * sizeof(char*));
Then, you can use the scanf() as per your previous code.
Do this instead, together with the rest of the body:
int string_size;
//this begins just after reading T
scanf("%d", &string_size);
char **new_arrays = malloc(T * sizeof(char*));
for(i = 0; i < T; i++)
{
new_arrays[i] = malloc(string_size * sizeof(char));
}
The first malloc is to specify how many strings you want, and the second malloc is to specify how big a string can be.
Further tips:
When you're writing in C, do not cast void* produced by malloc and realloc.
You should de-allocate the memory used in the reverse way:
for (i = 0; i < T; ++i)
{
free(new_array[i]);
}
free(new_array);
Always check if the memory allocation process is (un)succesful:
char **new_arrays = malloc(T * sizeof(char*));
if(new_arrays == NULL)
exit(0) //e.g.
for(i = 0; i < T; i++)
{
new_arrays[i] = malloc(string_size * sizeof(char));
if(new_arrays[i] == NULL)
exit(0) //e.g.
}
Check if the user provides valid values through scanf.
Thanks everyone. The length of the strings in the char* array can not be greater than 1000 chars so thats hard coded. Here is the final working code...
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main()
{
int T;
int i;
scanf("%d",&T);
char **new_array = malloc(T * sizeof(char*));
for (i = 0; i < T ; i++)
{
new_array[i] = malloc(1000 * sizeof(char));
scanf("%s", new_array[i]);
}
for (i = 0; i < T; i++)
printf("%s\n", new_array[i]);
}
What is the right way to initialize char** ?
I get coverity error - Uninitialized pointer read (UNINIT) when trying:
char **values = NULL;
or
char **values = { NULL };
This example program illustrates initialization of an array of C strings.
#include <stdio.h>
const char * array[] = {
"First entry",
"Second entry",
"Third entry",
};
#define n_array (sizeof (array) / sizeof (const char *))
int main ()
{
int i;
for (i = 0; i < n_array; i++) {
printf ("%d: %s\n", i, array[i]);
}
return 0;
}
It prints out the following:
0: First entry
1: Second entry
2: Third entry
Its fine to just do char **strings;, char **strings = NULL, or char **strings = {NULL}
but to initialize it you'd have to use malloc:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(){
// allocate space for 5 pointers to strings
char **strings = (char**)malloc(5*sizeof(char*));
int i = 0;
//allocate space for each string
// here allocate 50 bytes, which is more than enough for the strings
for(i = 0; i < 5; i++){
printf("%d\n", i);
strings[i] = (char*)malloc(50*sizeof(char));
}
//assign them all something
sprintf(strings[0], "bird goes tweet");
sprintf(strings[1], "mouse goes squeak");
sprintf(strings[2], "cow goes moo");
sprintf(strings[3], "frog goes croak");
sprintf(strings[4], "what does the fox say?");
// Print it out
for(i = 0; i < 5; i++){
printf("Line #%d(length: %lu): %s\n", i, strlen(strings[i]),strings[i]);
}
//Free each string
for(i = 0; i < 5; i++){
free(strings[i]);
}
//finally release the first string
free(strings);
return 0;
}
There is no right way, but you can initialize an array of literals:
char **values = (char *[]){"a", "b", "c"};
or you can allocate each and initialize it:
char **values = malloc(sizeof(char*) * s);
for(...)
{
values[i] = malloc(sizeof(char) * l);
//or
values[i] = "hello";
}