how to malloc a whole array at onec? In C - c

# define size_of_files 100
char* file_paths[size_of_files];
for(int file_path_idx = 0; file_path_idx < N; file_path_idx++)
{
file_paths[file_path_idx] =(char*)malloc(strlen(fpath)+1);
strcpy(file_paths[file_path_idx],fpath);
}
How to have malloc for file_paths array at ones not for every idx in file_path
what i need is to have file_paths[file_path_idx] =(char*)malloc(strlen(fpath)+1); above the for loop and rhe strcpy will work fine?

You can allocate a single block of memory containing size_of_files * (strlen(fpath)+1) bytes. Then you can index into this when making copies of fpath
# define size_of_files 100
char* file_paths[size_of_files];
size_t pathlen = strlen(fpath)+1;
char *all_paths = malloc(size_of_files * pathlen);
for(int file_path_idx = 0; file_path_idx < N; file_path_idx++)
{
file_paths[file_path_idx] = &all_paths[file_path_idx * pathlen];
strcpy(file_paths[file_path_idx], fpath);
}

Related

Try to split string but got messy substrings

I try to split one string to 3-gram strings. But turns out that the resulting substrings were always messy. The length and char ** input... are needed, since I will use them as args later for python calling the funxtion.
This is the function I wrote.
struct strArrIntArr getSearchArr(char* input, int length) {
struct strArrIntArr nameIndArr;
// flag of same bit
int same;
// flag/index of identical strings
int flag = 0;
// how many identical strings
int num = 0;
// array of split strings
char** nameArr = (char **)malloc(sizeof(char *) * (length - 2));
if ( nameArr == NULL ) exit(0);
// numbers of every split string
int* valueArr = (int* )malloc(sizeof(int) * (length-2));
if ( valueArr == NULL ) exit(0);
// loop length of search string -2 times (3-gram)
for(int i = 0; i<length-2; i++){
if(flag==0){
nameArr[i - num] = (char *)malloc(sizeof(char) * 3);
if ( nameArr[i - num] == NULL ) exit(0);
printf("----i------------%d------\n", i);
printf("----i-num--------%d------\n", i-num);
}
flag = 0;
// compare splitting string with existing split strings,
// if a string exists, it would not be stored
for(int k=0; k<i-num; k++){
same = 0;
for(int j=0; j<3; j++){
if(input[i + j] == nameArr[k][j]){
same ++;
}
}
// identical strings found, if all the three bits are the same
if(same == 3){
flag = k;
num++;
break;
}
}
// if the current split string doesn't exist yet
// put current split string to array
if(flag == 0){
for(int j=0; j<3; j++){
nameArr[i-num][j] = input[i + j];
valueArr[i-num] = 1;
}
}else{
valueArr[flag]++;
}
printf("-----string----%s\n", nameArr[i-num]);
}
// number of N-gram strings
nameIndArr.length = length- 2- num;
// array of N-gram strings
nameIndArr.charArr = nameArr;
nameIndArr.intArr = valueArr;
return nameIndArr;
}
To call the function:
int main(int argc, const char * argv[]) {
int length = 30;
char* input = (char *)malloc(sizeof(char) * length);
input = "googleapis.com.wncln.wncln.org";
// split the search string into N-gram strings
// and count the numbers of every split string
struct strArrIntArr nameIndArr = getSearchArr(input, length);
}
Below is the result. The strings from 17 are messy.
----i------------0------
----i-num--------0------
-----string----goo
----i------------1------
----i-num--------1------
-----string----oog
----i------------2------
----i-num--------2------
-----string----ogl
----i------------3------
----i-num--------3------
-----string----gle
----i------------4------
----i-num--------4------
-----string----lea
----i------------5------
----i-num--------5------
-----string----eap
----i------------6------
----i-num--------6------
-----string----api
----i------------7------
----i-num--------7------
-----string----pis
----i------------8------
----i-num--------8------
-----string----is.
----i------------9------
----i-num--------9------
-----string----s.c
----i------------10------
----i-num--------10------
-----string----.co
----i------------11------
----i-num--------11------
-----string----com
----i------------12------
----i-num--------12------
-----string----om.
----i------------13------
----i-num--------13------
-----string----m.w
----i------------14------
----i-num--------14------
-----string----.wn
----i------------15------
----i-num--------15------
-----string----wnc
---i------------16------
----i-num--------16------
-----string----ncl
----i------------17------
----i-num--------17------
-----string----clnsole
----i------------18------
----i-num--------18------
-----string----ln.=C:
----i------------19------
----i-num--------19------
-----string----n.wgram 馻绚s
----i------------20------
----i-num--------20------
-----string----n.wgram 馻绚s
-----string----n.wgram 馻绚s
-----string----n.wgram 馻绚s
-----string----n.wgram 馻绚s
-----string----n.wgram 馻绚s
-----string----n.oiles(騛窑=
----i------------26------
----i-num--------21------
-----string----.orSModu鯽蓼t
----i------------27------
----i-num--------22------
-----string----org
under win10, codeblocks 17.12, gcc 8.1.0
You are making life complicated for you in several places:
Don't count backwards: Instead of making num the count of duplicates, make it the count of unique trigraphs.
Scope variable definitions in functions as closely as possible. You have several uninitialized variables. You have declared them at the start of the function, but you need them only in local blocks.
Initialize as soon as you allocate. In your code, you use a flag to determine whather to create a new string. The code to allocate he string and to initialize it are in different blocks. Those blocks have the same flag as condition, but the flag is updated in between. This could lead to asynchronities, even to bugs when you try to initialize memory that wasn't allocated.
It's probably better to keep the strings and their counts together in a struct. If anything, this will help you with sorting later. This also offers some simplification: Instead of allocating chunks of 3 bytes, keep a char array of four bytes in the struct, so that all entries can be properly null-terminated. Those don't need to be allocated separately.
Here's an alternative implementation:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct tri {
char str[4]; // trigraph: 3 chars and NUL
int count; // count of occurrences
};
struct stat {
struct tri *tri; // list of trigraphs with counts
int size; // number of trigraphs
};
/*
* Find string 'key' in list of trigraphs. Return the index
* or in the array or -1 if it isn't found.
*/
int find_trigraph(const struct tri *tri, int n, const char *key)
{
for (int i = 0; i < n; i++) {
int j = 0;
while (j < 3 && tri[i].str[j] == key[j]) j++;
if (j == 3) return i;
}
return -1;
}
/*
* Create an array of trigraphs from the input string.
*/
struct stat getSearchArr(char* input, int length)
{
int num = 0;
struct tri *tri = malloc(sizeof(*tri) * (length - 2));
for(int i = 0; i < length - 2; i++) {
int index = find_trigraph(tri, num, input + i);
if (index < 0) {
snprintf(tri[num].str, 4, "%.3s", input + i); // see [1]
tri[num].count = 1;
num++;
} else {
tri[index].count++;
}
}
for(int i = 0; i < num; i++) {
printf("#%d %s: %d\n", i, tri[i].str, tri[i].count);
}
struct stat stat = { tri, num };
return stat;
}
/*
* Driver code
*/
int main(void)
{
char *input = "googleapis.com.wncln.wncln.org";
int length = strlen(input);
struct stat stat = getSearchArr(input, length);
// ... do stuff with stat ...
free(stat.tri);
return 0;
}
Footnote 1: I find that snprintf(str, n, "%.*s", len, str + offset) is useful for copying substrings: The result will not overflow the buffer and it will be null-terminated. There really ought to be a stanard function for this, but strcpy may overflow and strncpy may leave the buffer unterminated.
This answer tries to fix the existing code instead of proposing alternative/better solutions.
After fixing the output
printf("-----string----%s\n", nameArr[i-num]);
in the question, there is still another important problem.
You want to store 3 characters in nameArr[i-num] and allocate space for 3 characters. Later you print is as a string in the code shown above. This requires a trailing '\0' after the 3 characters, so you have to allocate memory for 4 characters and either append a '\0' or initialize the allocated memory with 0. Using calloc instead of malloc would automatically initialize the memory to 0.
Here is a modified version of the source code
I also changed the initialization of the string value and its length in main() to avoid the memory leak.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct strArrIntArr {
int length;
char **charArr;
int *intArr;
};
struct strArrIntArr getSearchArr(char* input, int length) {
struct strArrIntArr nameIndArr;
// flag of same bit
int same;
// flag/index of identical strings
int flag = 0;
// how many identical strings
int num = 0;
// array of split strings
char** nameArr = (char **)malloc(sizeof(char *) * (length - 2));
if ( nameArr == NULL ) exit(0);
// numbers of every split string
int* valueArr = (int* )malloc(sizeof(int) * (length-2));
if ( valueArr == NULL ) exit(0);
// loop length of search string -2 times (3-gram)
for(int i = 0; i<length-2; i++){
if(flag==0){
nameArr[i - num] = (char *)malloc(sizeof(char) * 4);
if ( nameArr[i - num] == NULL ) exit(0);
printf("----i------------%d------\n", i);
printf("----i-num--------%d------\n", i-num);
}
flag = 0;
// compare splitting string with existing split strings,
// if a string exists, it would not be stored
for(int k=0; k<i-num; k++){
same = 0;
for(int j=0; j<3; j++){
if(input[i + j] == nameArr[k][j]){
same ++;
}
}
// identical strings found, if all the three bits are the same
if(same == 3){
flag = 1;
num++;
break;
}
}
// if the current split string doesn't exist yet
// put current split string to array
if(flag == 0){
for(int j=0; j<3; j++){
nameArr[i-num][j] = input[i + j];
valueArr[i-num] = 1;
}
nameArr[i-num][3] = '\0';
}else{
valueArr[flag]++;
}
printf("-----string----%s\n", nameArr[i-num]);
}
// number of N-gram strings
nameIndArr.length = length- 2- num;
// array of N-gram strings
nameIndArr.charArr = nameArr;
nameIndArr.intArr = valueArr;
return nameIndArr;
}
int main(int argc, const char * argv[]) {
int length;
char* input = strdup("googleapis.com.wncln.wncln.org");
length = strlen(input);
// split the search string into N-gram strings
// and count the numbers of every split string
struct strArrIntArr nameIndArr = getSearchArr(input, length);
}
This other answer contains more improvements which I personally would prefer over the modified original solution.

how to use a 2D array in C

I am new in C and I am trying to create a 2D array of chars.
The logic behind this is to get unknown amount of string inputs
from the user and to be able to get to those strings
(each string ends with a ":") but when I tried to debug I got:
<Error reading characters of string>
This is the code:
int main()
{
int j = 0, rows = 50;
int i=0, lines = 50;
char **names;
names = (char**)malloc(lines*sizeof(char*));
if (i >= lines)
{
names = (char**)realloc(names, 10 * sizeof(char*));
lines = lines * 10;
}
for (j ; names[i][j] != ':'; j++)
{
*names = (char*)malloc(rows * sizeof(char));
if (j >= rows)
{
*names = (char*)realloc(names, 10 * sizeof(char));
rows = rows * 10;
}
scanf("%c", &names[i][j]);
}
i++;
return 0;
}
for (j ; names[i][j] != ':'; j++)
In this loop your test condition tests for ':' in names . names has been allocated memory but it does not contain any content (what will it compare to ?).
Use a do-while loop , in order to execute loop before reading characters in names.
Also you allocate memory for char *'s but you don't allocate memory to these pointers correctly . And without allocating memory correctly you try to store characters at location they point to . This will cause problem .
Allocate memory to each char * and then take input .
Some this like this can be done -
do{
names[i] =malloc(rows * sizeof(char));
if(names!=NULL){
if (j >= rows)
{
*names = (char*)realloc(names, 10 * sizeof(char));
rows = rows * 10;
}
scanf("%c", &names[i][j]);
j++;
i++;
}
}while(names[i][j]!=':')'
Note-
1. You should free the allocated memory . And you first if will not execute (can't understand its use ).
2. Check return of malloc.

realloc() seems to affect already allocated memory

I am experiencing an issue where the invocation of realloc seems to modify the contents of another string, keyfile.
It's supposed to run through a null-terminated char* (keyfile), which contains just above 500 characters. The problem, however, is that the reallocation I perform in the while-loop seems to modify the contents of the keyfile.
I tried removing the dynamic reallocation with realloc and instead initialize the pointers in the for-loop with a size of 200*sizeof(int) instead. The problem remains, the keyfile string is modified during the (re)allocation of memory, and I have no idea why. I have confirmed this by printing the keyfile-string before and after both the malloc and realloc statements.
Note: The keyfile only contains the characters a-z, no digits, spaces, linebreaks or uppercase. Only a text of 26, lowercase letters.
int **getCharMap(const char *keyfile) {
char *alphabet = "abcdefghijklmnopqrstuvwxyz";
int **charmap = malloc(26*sizeof(int));
for (int i = 0; i < 26; i++) {
charmap[(int) alphabet[i]] = malloc(sizeof(int));
charmap[(int) alphabet[i]][0] = 0; // place a counter at index 0
}
int letter;
int count = 0;
unsigned char c = keyfile[count];
while (c != '\0') {
int arr_count = charmap[c][0];
arr_count++;
charmap[c] = realloc(charmap[c], (arr_count+1)*sizeof(int));
charmap[c][0] = arr_count;
charmap[c][arr_count] = count;
c = keyfile[++count];
}
// Just inspecting the results for debugging
printf("\nCHARMAP\n");
for (int i = 0; i < 26; i++) {
letter = (int) alphabet[i];
printf("%c: ", (char) letter);
int count = charmap[letter][0];
printf("%d", charmap[letter][0]);
if (count > 0) {
for (int j = 1; j < count+1; j++) {
printf(",%d", charmap[letter][j]);
}
}
printf("\n");
}
exit(0);
return charmap;
}
charmap[(int) alphabet[i]] = malloc(sizeof(int));
charmap[(int) alphabet[i]][0] = 0; // place a counter at index 0
You are writing beyond the end of your charmap array. So, you are invoking undefined behaviour and it's not surprising that you are seeing weird effects.
You are using the character codes as an index into the array, but they do not start at 0! They start at whatever the ASCII code for a is.
You should use alphabet[i] - 'a' as your array index.
The following piece of code is a source of troubles:
int **charmap = malloc(26*sizeof(int));
for (int i = 0; i < 26; i++)
charmap[...] = ...;
If sizeof(int) < sizeof(int*), then it will be performing illegal memory access operations.
For example, on 64-bit platforms, the case is usually sizeof(int) == 4 < 8 == sizeof(int*).
Under that scenario, by writing into charmap[13...25], you will be accessing unallocated memory.
Change this:
int **charmap = malloc(26*sizeof(int));
To this:
int **charmap = malloc(26*sizeof(int*));

Allocate a 3D char array in C (char ***)

I would like to allocate a char***.
I have a got a sentence like this: "This is a command && which I || need to ; split"
I need to put in each box a full sentence just like that:
cmd[0] = "This is a command"
cmd[1] = "wich I"
cmd[2] = "need to"
cmd[3] = "split"
Sentences are separated by tokens like &&, ||, ;, |.
My problem is that I don't know how to allocate my triple dimension array.
I always get a Segmentation Fault.
This is what I do :
for(k = 0; k < 1024; k++)
for( j = 0; j < 1024; j++)
cmd[k][j] = malloc(1024);
But a few line later, in an other loop :
» cmd[k][l] = array[i];
I get a segfault here.
How can I do this please ?
Thanks in advance
Please keep in mind that a 2/3D array in C is not the same as a char ***.
If all you wish is to have a 1024^3 character array then you will be good with
char array[1024][1024][1024];
But keep in mind that this will allocate 1 GB of space on your stack which may or may not work.
To allocate this much on the heap you need to type it correctly:
char (*array)[1024][1024] = malloc(1024*1024*1024);
In this scenario array is a pointer to an array of 2D 1024x1024 character matrices.
If you really want to work with char *** (which I do not recommend if your array lengths are static) then you need to allocate all intermediary arrays too:
char *** cmd = malloc(sizeof(char **) * 1024);
for(k = 0; k < 1024; k++) {
cmd[k] = malloc(sizeof(char *) * 1024);
for( j = 0; j < 1024; j++)
cmd[k][j] = malloc(1024);
}
If you are going to be splitting your string by delimiters that are longer then a single character then this is how you could do it with string search.
The following function will accept an input string and a delimiter string.
It will return a char ** which has to be freed and it will destroy your input string (reusing it's memory to store the tokens).
char ** split_string(char * input, const char * delim) {
size_t num_tokens = 0;
size_t token_memory = 16; // initialize memory initially for 16 tokens
char ** tokens = malloc(token_memory * sizeof(char *));
char * found;
while ((found = strstr(input, delim))) { // while a delimiter is found
if (input != found) { // if the strind does not start with a delimiter
if (num_tokens == token_memory) { // increase the memory array if it is too small
void * tmp = realloc(tokens, (token_memory *= 2) * sizeof(char *));
if (!tmp) {
perror("realloc"); // out of memory
}
tokens = tmp;
}
tokens[num_tokens++] = input;
*found = '\0';
}
// trim off the processed part of the string
input = found + strlen(delim);
}
void * tmp = realloc(tokens, (num_tokens +1) * sizeof(char *));
if (!tmp) {
perror("realloc"); // something weird happened
}
tokens = tmp;
// this is so that you can count the amount of tokens you got back
tokens[num_tokens] = NULL;
return tokens;
}
You will need to recursively run this to split by more then one delimiter.

problem in char array?

char *funcNames[]= {"VString","VChar","VArray","VData"};
for(int i=0;i<4;i++)
{
char* temp = funcNames[i];
int len = strlen(funcNames[i]);
for(int j = 0;j<len ;j++)
{
if(j!=0)
{
char arr = temp[j];
}
}
}
here i want to separate "V" from all string in char array ...and create another char array without "V" in starting of the string.i want another char array {String,char,array,data}...i cant make a char array ....help me to solve my issue...
Do you really need a copy? You could just make a new array pointing into the original strings:
char *newArray[4];
for (i = 0; i < 4; i++) {
newArray[i] = funcNames[i] + 1;
}
If you do need to make copies then you'll have to use dynamical allocation to create the buffers to hold the copies. What you will do is declare an array of pointers and place an allocated string buffer in each of the array's entries:
char *newArray[4];
for (i = 0; i < 4; i++) {
newArray[i] = malloc(sizeof(char) * streln(funcNames[0]));
strcpy(newArray[i], funcNames[i] + 1);
}
You will have to call free() on each allocated buffer.
Or if you don't want to do allocation and are know the maximum length of the strings in funcNames:
#define MAX_FUNC_NAME_LEN 32
char newArray[4][MAX_FUNC_NAME_LEN];
for (i = 0; i < 4; i++) {
strcpy(newArray[i], funcNames[i] + 1);
}
There's only small differences between arrays and pointers so I'd opt for:
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main (void) {
int i;
char *funcNames[]= {"VString","VChar","VArray","VData"};
// This is the code that dupicates your strings by allocating an array,
// then allocating each string within that array (and copying).
// Note we use strlen, not strlen+1 to mallocsince we're replacing the
// 'V' at the start with the zero byte at the end. Also we strcpy
// from char offset 1, not 0 (to skip the fist char).
char **newNames = malloc (sizeof(char*) * sizeof(funcNames) / sizeof(*funcNames));
assert (newNames != NULL);
for (i = 0; i < sizeof(funcNames) / sizeof(*funcNames); i++) {
newNames[i] = malloc (strlen (funcNames[i]));
assert (newNames[i] != NULL);
strcpy (newNames[i], funcNames[i] + 1);
}
/* Use your newNames here */
for (i = 0; i < sizeof(funcNames) / sizeof(*funcNames); i++) {
printf ("funcNames[%d] #%08x = '%s'\n", i, funcNames[i], funcNames[i]);
printf (" newNames[%d] #%08x = '%s'\n", i, newNames[i], newNames[i]);
putchar ('\n');
}
// Finished using them.
// Free the strings themselves, then free the array.
for (i = 0; i < sizeof(funcNames) / sizeof(*funcNames); i++)
free (newNames[i]);
free (newNames);
return 0;
}
You can see from the output that the locations of the variables in memory are different and that the content of the new strings is what you wanted:
funcNames[0] #00402000 = 'VString'
newNames[0] #006601c0 = 'String'
funcNames[1] #00402008 = 'VChar'
newNames[1] #006601d0 = 'Char'
funcNames[2] #0040200e = 'VArray'
newNames[2] #006601e0 = 'Array'
funcNames[3] #00402015 = 'VData'
newNames[3] #006601f0 = 'Data'

Resources