I keep getting 4 "Passing argument 1 of strcpy makes pointer from integer without a cast" error message each time I am trying to write a string to a dynamically allocated array of strings. I know that it has to do with my strcpy call obviously, and that it's a type mismatch issue somewhere, but I need a little assistance on this please.
/* ---- LIBRARIES ---- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ---- PROTOTYPES ---- */
int readFx(char** arr);
/* int sortFx(char** arr, int arg2);
int printFx(char** arr, int arg2); */
int freeFx(char** arr, int cnt);
char* getToken(char arr1[], int loc);
void makeRoom(char*** t, int size);
/* ---- MAIN ---- */
int main(void)
{
char** pntrArr;
char* fileText;
int iniArrSize = 10;
int recCnt = 0;
/* array to store addresses of arrays forming the rows */
pntrArr = malloc(iniArrSize * sizeof(char*));
recCnt = readFx(pntrArr);
sortFx(pntrArr, recCnt);
/* printFx(pntrArr, recCnt); */
freeFx(pntrArr, recCnt);
return;
}
/* ---- FUNCTIONS ---- */
int readFx(char** arr)
{
/*
input: csv file of string arrays
output: count of records received
purpose: read file, store values in array and populate pointer array
*/
char buffer[350];
char temp[350];
char*** reallocTemp;
char* token;
int counter, index;
int subLoc = 3;
int enrLoc = 8;
int arrSize = 10;
/* Clear headers */
fgets(buffer, sizeof(buffer), stdin);
counter = 0;
/* While file stream is not null */
while (fgets(buffer, sizeof(buffer), stdin) != NULL)
{
/* Populate array within array if pntr arr has room */
if(counter <= arrSize)
{
/* buffer copy*/
strcpy(temp, buffer);
index = 0;
/* create array for token values */
arr[counter] = malloc(10 * sizeof(char));
/* Get first token */
token = getToken(temp, subLoc);
strcpy(arr[counter][index],token);
index++;
/* Get second token */
token = getToken(temp, enrLoc);
strcpy(arr[counter][index], token);
counter++;
}
else
{
/* Reallocate memory due to necessary expansion */
makeRoom(&arr, arrSize);
/* Realloc was successful */
if(temp != NULL)
{
arrSize = arrSize * 2;
/* Print Reallocation info */
printf("reallocating to %d", arrSize);
/* Populate values for current buffer now that you have realloc'd */
/* buffer copy*/
strcpy(temp, buffer);
index = 0;
/* create array for token values */
arr[counter] = malloc(10 * sizeof(char));
/* Get first token */
token = getToken(temp, enrLoc);
strcpy(arr[counter][index], token);
index++;
/* Get second token */
token = getToken(temp, subLoc);
strcpy(arr[counter][index], token);
counter++;
}
else
{
printf("unable to reallocate\n");
exit(1);
}
}
return counter;
}
char* getToken(char arr1[], int loc)
{
/*
input: string array & location of desired string
output: string of token at position
purpose: grab string (char*) of certain position in given array
*/
int loopCnt;
char* del = ",\n";
/* Grab first token */
char* token = strtok(buffer, del);
/* Loop through array to grab value at given location */
for(loopCnt = 1; loopCnt < loc; loopCnt++)
{
token = strtok(NULL, del);
}
return token;
}
int freeFx(char** arr, int cnt)
{
int i;
for(i = 0; i < cnt; i++)
{
free(arr[i]);
}
free( arr );
return 0;
}
void makeRoom(char*** t, int size)
{
*t = realloc(*t, size * 2 * sizeof(char*));
}
From code :
strcpy(arr[counter][index],token);
arr[counter][index] refers to the single character of the array, so please use arr[counter] instead of that (which is pointer to the dynamically allocated block),
so that you can copy the string to that dynamic array.
Adding extra details, if you use strcpy as below,
strcpy(arr[counter][index],token);
Still the copy is done but, not in the correct location,
Suppose arr[counter] holds the address of a char pointer which is 1000.
So strcpy(arr[counter][index],token); will copy the string in the address 1000 + index.
strcpy(arr[counter],token) will copy the string in the address 1000
Hope this is helpful.
Related
So I'm currently trying to write a C program to track the longest word(s) from argv.
It's been going great! Until I tried to reallocate a character double pointer, it seems to think it's an invalid pointer.
The exact error I'm getting is;
realloc(): invalid pointer
fish: Job 1, './longest-strings.o hello...' terminated by signal SIGABRT (Abort)
I'm creating this double character pointer through the return of a function, is this possibly the error? I'm pretty sure my use of realloc is correct, and I can't quite seem to trace the issue.
Any help would be massively appreciated!
/*
* Author: Smallblue2
* Description: Program finds the longest word in an input string
*
* Input: A string from cmd line
* Output: The longest word in a string
*/
// Header files
#include <stdio.h>
#include <stdlib.h>
// Function prototypes
int stringLength(char *string);
void longestWords(char **strings, int amt);
char **reset(char *string);
void display(char **longest, int len_array);
// Main function
int main(int argc, char **argv)
{
char **strings = &*(argv + 1);
longestWords(strings, argc - 1);
return 0;
}
// Find the length of a string
int stringLength(char *string)
{
int length = 0;
while (*string != '\0')
{
length++;
string++;
}
return length;
}
// Finds the longest word(s) from argv
void longestWords(char **strings, int amt)
{
// Set up variables & pointers
int len_array = 1;
// Assign the first string to be the longest
char **longest = reset(*(strings));
int longest_len = stringLength(*(longest));
int length = 0;
// Loop through the rest of the strings
for (int i = 1; i < amt; i++)
{
// Find the length of the current string
length = stringLength(*(strings + i));
// If it is larger, reset the longest array and place the
// new string inside
if (length > longest_len)
{
longest_len = length;
longest = reset(*(strings + i));
len_array = 1;
// Else, expand the longest array's memory and add the
// additional string inside
} else if (length == longest_len) {
len_array++;
char **temp_longest = (char **)realloc(longest, len_array * sizeof(char *));
if (!longest)
{
printf("Error: Memory allocation failed!\n");
free(longest);
return;
}
longest = temp_longest;
*(longest + len_array - 1) = *(strings + i);
}
}
// Display the longest word(s)
display(longest, len_array);
free(longest);
longest = NULL;
return;
}
// Resets the longest word array
char **reset(char *string)
{
char **longest = (char **)malloc(sizeof(char *));
if (!longest)
{
printf("Error: Memory Allocation Failed!\n");
return NULL;
}
longest = &string;
return longest;
}
// Displays the longest word(s)
void display(char **longest, int len_array)
{
for (int i = 0; i < len_array; i++)
{
printf("%s\n", *(longest + i));
}
return;
}
I've tried to use both calloc and malloc, I tried executing the script where realloc wouldn't occur and then apparently free() believes there's an invalid pointer too. Really lost here.
Here are the two minimal changes:
stringLength should handle a NULL pointer.
int stringLength(char *string)
{
int length = 0;
while (string && *string != '\0')
{
length++;
string++;
}
return length;
}
Or perhaps:
#include <string.h>
size_t stringLength(char *string)
{
return string ? strlen(string) : 0;
}
reset() leaks the memory you just allocated, and you don't want to take the address of an argument which is out of scope when the function returns. Not entirely sure what the point of the function is but try this instead:
char **reset(char *string)
{
char **longest = malloc(sizeof(char *));
if (!longest)
{
printf("Error: Memory Allocation Failed!\n");
return NULL;
}
*longest = string;
return longest;
}
and example output:
$ ./a.out hello...
hello...
./a.out hello world!
world!
I need to dynamically append a char to a string, so I'm using realloc() to add more memory as I need it.
I'm new to C (coming from Python) so I've been reading a lot and this was the best I could do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void append_to(char *array, char value) {
size_t buffer = (strlen(array) * sizeof(char)) + sizeof(char);
char *new_array = realloc(array, buffer);
if (new_array == NULL) {
printf("CRITICAL ERROR\n");
exit(-1);
}
array = new_array;
int position = strlen(array);
array[position] = value;
}
int main() {
char *list = malloc(sizeof(char));
for (int i = 1; i < 26; i++){
append_to(list, 'a');
printf("%d -> %s\n", i, list);
}
}
This is just an example to showcase the issue. The code runs flawlessly until iteration 24, see below:
1 -> a
2 -> aa
[...] //omitted
23 -> aaaaaaaaaaaaaaaaaaaaaaa
24 -> aaaaaaaaaaaaaaaaaaaaaaaa
25 ->
What am I missing?
First you forget to add another NUL char at the end of your c-string.
Second, realloc may change the memory location of the data, but you passed the list as value, so the relocation is not visible in the case of data relocation.
That should lokks like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void append_to(char **array, char value) { // pass pointer's address
size_t buffer = (strlen(*array) * sizeof(char)) + sizeof(char) + sizeof(char); // one more to tackle the end of the string
char *new_array = realloc(*array, buffer);
if (new_array == NULL) {
printf("CRITICAL ERROR\n");
exit(-1);
}
*array = new_array;
int position = strlen(*array);
(*array)[position] = value;
(*array)[position+1] = 0; // end of string
}
int main() {
char *list = malloc(sizeof(char));
list[0] = 0; // end of string
for (int i = 1; i < 26; i++){
append_to(&list, 'a'); // pass address of array so that it can be changed by the call
printf("%d -> %s\n", i, list);
}
free(list); // always explicitly free unused resources
}
You didn't receive array as a double pointer, so you can't reassign the caller's pointer when realloc has to move the allocation.
To fix,
// Receive double pointer
void append_to(char **array, char value) {
// Add dereferencing as needed
size_t buffer = (strlen(*array) + 2) * sizeof(char);
char *new_array = realloc(*array, buffer);
if (new_array == NULL) {
printf("CRITICAL ERROR\n");
exit(-1);
}
*array = new_array;
int position = strlen(*array);
array[0][position] = value;
array[0][position+1] = '\0'; // Explicitly NUL terminate, don't assume new memory is zeroed
}
int main() {
char *list = malloc(sizeof(char));
for (int i = 1; i < 26; i++){
append_to(&list, 'a'); // Pass address of list
printf("%d -> %s\n", i, list);
}
}
How would I assign the value from strtok() to an array that's in a struct? Inside my struct I have char *extraRoomOne and in my main I have:
while (token!= NULL)
{
token = strtok(NULL, " ");
certainRoom.extraRoomOne[counter] = token;
}
Compiler is telling me to dereference it, but when I do I get a seg fault.
typedef struct room{
char *extraRoomOne;
}room;
In main, all I had was `room certainRoom;
Edit: changed char *extraRoomOne to char **extraRoomOne
Now I have:
token = strtok(NULL," ");
certainRoom.extraRoomOne = realloc(certainRoom.extraRoomOne,(counter + 1) * sizeof(char *));
certainRoom.extraRoomOne[counter] = malloc(strlen(token)+1);
strcpy(certainRoom.extraRoomOne[counter],token);`
Is this the correct way of realloc and malloc? I increment the counter below each time as well
You should not do that assignment because strtok() returns a pointer to the string you passed in the first call and it will change it in subsequent calls, and the '\0' terminator can be moved by strtok() so the pointer will point to a different string at the end, but instead you can copy the string first allocating space for it with malloc() and then with strcpy()
size_t length;
length = strlen(token);
certainRoom.extraRoomOne = malloc(1 + length);
if (certainRoom.extraRoomOne != NULL)
strcpy(certainRoom.extraRoomOne, token);
you should remember to include string.h.
And if what you really want is to capture more than just one token, which would explain the while loop, you could do it this way
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct room{
char **tokens;
size_t count;
} room;
room
tokenizeString(char *string)
{
char *token;
room instance;
instance.tokens = NULL;
instance.count = 0;
token = strtok(string, " ");
while (token != NULL)
{
void *pointer;
size_t length;
pointer = realloc(instance.tokens, (1 + instance.count) * sizeof(char *));
if (pointer == NULL)
{
size_t i;
for (i = 0 ; i < instance.count ; ++i)
free(instance.tokens[i]);
free(instance.tokens);
instance.tokens = NULL;
instance.count = 0;
return instance;
}
instance.tokens = pointer;
length = strlen(token);
instance.tokens[instance.count] = malloc(1 + length);
if (instance.tokens[instance.count] != NULL)
strcpy(instance.tokens[instance.count], token);
instance.count += 1;
token = strtok(NULL, " ");
}
return instance;
}
int
main(int argc, char **argv)
{
room certainRoom;
size_t i;
if (argc < 1) /* invalid number of arguments */
return -1;
certainRoom = tokenizeString(argv[1]);
for (i = 0 ; i < certainRoom.count ; ++i)
{
printf("%s\n", certainRoom.tokens[i]);
/* we are done working with this token, release it */
free(certainRoom.tokens[i]);
}
/* all tokens where released, now released the main container,
* note, that this only contained the pointers, the data was
* in the space pointed to by these pointers. */
free(certainRoom.tokens);
return 0;
}
I read words from given file (dictionary) to single string and I assign the string to nth index of string array. But it does not work. Output of the for loop in the main() is always e3V\347 etc. and output of the for loop in the createWordTable() is always last word of dictionary. Here is my code
char** createWordTable();
char** createTable();
int main()
{
int i;
char **hashTable;
hashTable = createTable();
hashTable = createWordTable();
for (i=0; i< 338; i++) {
printf("%s \n",hashTable[i]);
}
return 0;
}
char** createWordTable(){
char word[20],**table;
FILE *dicFile;
table = createTable();
dicFile = fopen("smallDictionary.txt", "r");
if (dicFile == NULL) {
perror("error");
}
int wordCount = 0,endFile = 1;
while (endFile != EOF) {
endFile = fscanf(dicFile,"%s",word);
table[wordCount] = word;
wordCount = wordCount+1;
}
for (int i=0; i< 338; i++) {
printf("%s \n",table[i]);
}
return table;
}
char** createTable(){
char **table;
int i;
table = (char **)malloc(338 * sizeof(char *));
for (i=0; i<=338; i++) {
*table = (char *)malloc(25 * sizeof(char));
}
return table;
}
I changed code to this and its work! I defined global variable 'table' and removed pointers (also dynamic allocation functions). I'm very curious why pointers don't work with array of strings in C for this code (I know square brackets also mean 'pointer') ? Because i have no bad experience with integer arrays. Sorry for bad English, here is new code :`
char words[338][10];
int main()
{
createWordTable();
for (int i=0; i< 338; i++) {
printf("%s \n",words[i]);
}
return 0;
}
void createWordTable(){
char word[20];
FILE *dicFile;
dicFile = fopen("smallDictionary.txt", "r");
if (dicFile == NULL) {
perror("error");
}
int wordCount = 0;
while (!feof(dicFile)) {
fscanf(dicFile,"%s",word);
if(feof(dicFile)) break;
strcpy(words[wordCount], word);
wordCount = wordCount+1;
}
fclose(dicFile);
}`
You are losing your createTable() result. Store it separate pointer variables.
hashTable = createTable();
hashTable = createWordTable();
An option to return an array of strings from a function is to use double-NUL-terminated strings.
This data structure is a sequence of strings, one stored in memory after the other, each NUL-terminated, and with an additional NUL-terminator at the end, e.g.:
+---+---+---+---+---+-----+---+---+---+---+---+-----+-----+
| H | e | l | l | o | NUL | w | o | r | l | d | NUL | NUL |
+---+---+---+---+---+-----+---+---+---+---+---+-----+-----+
^^^^^^
Double-NUL at the end
You can return from the function the pointer to the first string, i.e. to the beginning of the sequence.
One of the great advantages of this data structure is that it has very good locality for strings in the array.
This data structure is not hard to implement, and it's easy to navigate, as you can see from the following source code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
char * build_string_array(void) {
const char * test_strings[] = {
"Hello",
"World",
"Hi",
"John",
"Connie"
};
int i;
char * p;
char * string_array;
int total_len;
/* Calculate total length of strings */
total_len = 0;
for (i = 0; i < ARRAY_SIZE(test_strings); i++) {
/* Update total length with current string. +1 for '\0' */
total_len += strlen(test_strings[i]) + 1;
}
/* Consider double-NUL termination */
total_len++;
/* Allocate memory for the resulting string array */
string_array = malloc(total_len);
if (string_array == NULL)
return NULL; /* error */
/* Copy source strings to the destination string array memory */
p = string_array;
for (i = 0; i < ARRAY_SIZE(test_strings); i++) {
strcpy(p, test_strings[i]);
p += (strlen(p) + 1); /* +1 to skip terminating NUL */
}
/* Terminate with double-NUL */
*p = '\0';
/* Return the address of the string array to the caller */
return string_array;
}
int main() {
char * test_string_array;
const char * p;
/* Create the test string array */
test_string_array = build_string_array();
if (test_string_array == NULL) {
printf("Error in creating array.\n");
return 1;
}
/* Print string array content */
for (p = test_string_array; *p != '\0'; p += (strlen(p) + 1)) {
printf("%s\n", p);
}
/* Free array memory */
free(test_string_array);
/* All right */
return 0;
}
You should fscanf directly into table[wordcount] or strcpy from word. Otherwise every entry will just point to word, which contains the last string in the file.
I'm C# man, new in C language working with points first time.
I have this function that works with malloc(), realloc() and free() at future:
char ** split(char * delimiter, char * input) {
int i = 0;
int size = sizeof(char *);
char ** tokens;
char * token;
char * state;
tokens = (char **) malloc(size);
if(tokens == NULL) {
printf("Allocation failed.");
return;
}
for(token = strtok_r(input, delimiter, &state);
token != NULL;
token = strtok_r(NULL, delimiter, &state),
i++, size *= i) {
tokens = (char **) realloc(tokens, size);
if(tokens == NULL) {
printf("Realloc failed.");
return;
}
tokens[i] = state;
}
return tokens;
}
when I call:
char * IPNumber = "127.0.01";
char * delimiter = ".";
char ** parts = split(delimiter, IPNumber);
it gives segmentation fault.
I'm looking for an explanation how to get(calculate) the size value to be used in the second argument of realloc() function. Thanks in advance.
Ok, I guessed what you intended was to return an array of strings:
include
char ** split(char * delimiter, char * input) {
int i;
char ** tokens;
char * token;
char * state;
tokens = (char **) malloc(sizeof(char *) * (2));
if(tokens == NULL) {
printf("Allocation failed.");
return NULL;
}
tokens[0]=(char *)1; /* one element populated */
tokens[1]=NULL; /* no tokens */
for(i=1, token = strtok_r(input, delimiter, &state);
token != NULL;
token = strtok_r(NULL, delimiter, &state),
i++) {
/* grow array by one element - originally made with 2 */
{
char **new =(char **) realloc(tokens, (i+2) * sizeof(char *));
if(new == NULL) {
printf("Realloc failed.");
free(tokens);
return NULL;
}
else
{
tokens = new;
tokens[i+1] = NULL; /* initialize new entry */
}
}
tokens[i] = token;
tokens[0] = (char *)i;
}
return tokens;
}
int main( void )
{
char str[] = "129.128.0.1";
char delim[] = ".";
char **ret;
ret = split( delim, str );
printf( "tokens = %d\n", (int)ret[0] );
printf( "tokens[1] = %s\n", ret[1] );
printf( "tokens[2] = %s\n", ret[2] );
printf( "tokens[3] = %s\n", ret[3] );
printf( "tokens[4] = %s\n", ret[4] );
printf( "tokens[5] = %s\n", ret[5] );
}
return explicit values, not garbage.
change in realloc function. You grow the array by one element during each loop.
Fix memory leak
save the value returned by strtok_r, not its private internal state variable.
the array is one larger then it needs to be, so make sure it gets initialized to NULL
entry zero of the array is the size, which should not overflow unless you are handling HUGE strings
The sizes of your malloc/calloc are wrong (you multiply by the intended count, which makes the array grow by count!)
On the first item: i=0, size=sizeof(char*);
On the second item i=1, size=sizeof(char) /*that is too small for two elements */
char ** split(char * delimiter, char * input) {
unsigned size , used;
char ** array = NULL;
char * token;
char * state;
size = used = 0;
for(token=strtok_r(input, delimiter, &state); token; token=strtok_r(NULL, delimiter, &state) ) {
if (used+1 >= size) {
size = size ? 2*size: 4;
array = realloc(array, size * sizeof *array);
if (!array) { printf("Realloc failed."); return NULL ; /*leak here*/ }
}
array[used++] = state;
}
/* NOTE: need a way to communicate the number of elements back to the caller */
if (array) array[used] = NULL;
return array;
}
UPDATE: here is a test driver
int main(void)
{
char stuff[] = "this is the stuff";
char **ppp;
unsigned idx;
ppp = split( " " , stuff);
for (idx = 0; ppp && ppp[idx]; idx++) {
fprintf(stdout, "%u: %s\n", idx, ppp[idx] );
}
return 0;
}
Complete rewrite. There are some issues with the original code as posted.
The reallocation size computation is incorrect.
The passing of a string constant to strtok_r is not valid. It modifies the first argument, so that could result in an access violation when passed the string literal.
The assignment of the token into the result array starts at position 1 instead of 0.
The assignment uses the state variable instead of the token (probably not at all the desired result and probably undefined behavior).
There is no way for the caller to know how many tokens are in the returned array.
A failed call to realloc does not free the original pointer, so it would leak.
So rather than attempt to describe the changes, I'll follow the same pattern as others and show what might be a cleaner implementation with a single allocation based on the max possible number of tokens.
char ** split(char * delimiter, char * input) {
int size;
int maxsize;
char ** tokens;
char * token;
char * state;
// compute max possible tokens, which is half the input length.
// Add 1 for the case of odd strlen result and another +1 for
// a NULL entry on the end
maxsize = strlen( input ) / 2 + 2;
tokens = (char**)malloc( maxsize * sizeof( char*) );
if(tokens == NULL) {
printf("Allocation failed.");
return NULL;
}
size = 0;
for(token = strtok_r(input, delimiter, &state);
token != NULL;
token = strtok_r(NULL, delimiter, &state) ) {
tokens[size++] = token;
}
assert( size < maxsize );
// Put a NULL in the last entry so the caller knows how many entries
// otherwise some integer value would need to be returned as an output
// parameter.
tokens[size] = NULL;
// NOTE: could use realloc from maxsize down to size if desired
return tokens;
}
Usage might look like the following. Note the use of strdup to avoid passing the string constant to the function:
char * IPNumber = strdup( "127.0.01" );
char * delimiter = ".";
char ** parts = split(delimiter, IPNumber);
int i;
if ( parts ) {
for ( i = 0; parts[i] != NULL; i++ )
printf( "%s\n", parts[i] );
free( parts );
}
free( IPNumber );
I was going to point out things to fix, but instead just rewrote it as follows:
char **split(char *delim, char *input)
{
char *save; /* saved state for strtok_r */
char **tmp, /* temporary result from realloc (for error handling) */
**res; /* result - NULL-terminated array of tokens */
int i, /* index of current/last token */
count; /* number of elements in res (including NULL) */
/* Allocate first element for res */
if ( !(res = malloc(sizeof(res[0]))) ) {
/* return NULL if malloc() fails */
fprintf(stderr,"split(): malloc() failed\n");
return NULL;
}
/* res[0] = first token, or NULL */
res[0] = strtok_r(input,delim,&save);
/* if it was a token, grab the rest. Last one will be the NULL
* returned from strtok_r() */
if (res[0])
i = 0;
count = 1;
do {
/* Resize res, for next token */
/* use a temporary pointer for realloc()'s result, so that
* we can check for failure without losing the old pointer */
if ( tmp = realloc(res, sizeof(res[0]) * ++count) )
res = tmp;
else {
/* if realloc() fails, free res and return NULL */
free(res);
fprintf(stderr,"split(): realloc() failed.\n");
return NULL;
}
/* get next token, or NULL */
res[++i] = strtok_r(NULL,delim,&save);
} while (res[i]); /* done when last item was NULL */
return res;
}
So the size for realloc is the number of elements needed, multiplied by the size of an element.
The above version of the code returns a NULL-terminated array. Another approach would be to return the number of array elements somehow (like via an int * or size_t * argument); but in any case you need a way for the caller to know where the end of the results array is.
Using strtok_r() for this also adds another catch: The original input string is not left intact. So you'll need to bear that in mind when using this (or your original) function as well -- either use it when you don't need to preserve the original string, or make a duplicate of the original first.