I am having an issue where some global char pointer arrays that I am trying to initialize become full of garbage data after the function that I initialized them in goes out of scope.
char *dept_vals[255];
char *num_vals[255];
char *day_vals[255];
char *bldg_vals[255];
char *instr_vals[255];
int start_vals[255];
int end_vals[255];
int sect_vals[255];
int room_vals[255];
int idx;
static int callback(void *NotUsed, int argc, char **argv, char **azColName)
{
int i = 0;
while(i < argc)
{
dept_vals[idx] = argv[i++];
num_vals[idx] = argv[i++];
start_vals[idx] = atoi(argv[i++]);
end_vals[idx] = atoi(argv[i++]);
day_vals[idx] = argv[i++];
sect_vals[idx] = atoi(argv[i++]);
bldg_vals[idx] = argv[i++];
room_vals[idx] = atoi(argv[i++]);
instr_vals[idx] = argv[i++];
idx++;
}
return 0;
}
When I print the values in a different function, the contents are incorrect. However, the values in the integer arrays that I initialized in the same function have the right values. I suspect that the way I am initializing the char pointer arrays is causing unexpected behavior, but I'm not completely sure what is the correct way to initialize them in this situation.
Code like
dept_vals[idx] = argv[i++];
copies the address of argv[i] into dept_vals[idx], but as you point out, that goes out of scope when you return. You want to copy the actual string:
dept_vals[idx] = malloc(strlen(argv[i]) + 1);
strcpy(dept_vals[idx], argv[i]);
++i;
Without knowing how you call the function, it just guessing.
If you use gcc try to replace:
... = argv[i++];
with
... = argv[i] ?strdup(argv[i]) :NULL; ++i;
and compile using with the options -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED.
strdup() duplicates the "string" being passed.
Related
I'm trying to create a function that takes two input strings, dest and src, and appends the src string to the dest string.
Below is the current function I have. However, when I try to use it, I
get an error stating "returning 'char' from a function without a cast." I understand that my error involves the return statement and how I'm using it as a pointer, but I'm unsure how to fix it.
char* strcat(char dest[], char src[]) {
int destL = lenstr(dest);
int srcL = lenstr(src);
char result[destL + srcL];
int i;
for(i = 0; i < destL; i++){
result[i] = dest[i];
}
for(i = destL; i < destL+srcL; i++){
result[i] = src[i-destL];
}
return *result;
}
The lenstr function is:
int lenstr(char* s) {
int len = 0;
while(s[len++] != '\0');
return len-1;
}
You cannot return a locally declared array. Well you can, but the data may be overwritten at any time since it is no longer valid.
What you need to do is something like this:
char* strcat(char dest[], char src[]) {
char * result = malloc((lenstr(dest)+lenstr(src)+1) * sizeof *result);
// Code to copy data
return result;
}
Note that +1 is important to make room for the \0 terminator.
However, when I try to use it, I get an error stating "returning 'char' from a function without a cast."
This error simply indicates that your return value doesn't match the function declaration. In your function declaration, you have mentioned that it returns a char *. However, in your actual return statement, you are returning *result which is a dereferenced char pointer i.e. a char.
The second problem in your code is that you are returning an array from the function. Memory allocated using an array in a method becomes unavailable to the caller method. You need to create memory on heap and return a pointer to it and then let the caller free up the memory after usage.
Checkout the following working code:
char* strcat1(char dest[], char src[]) {
int destL = lenstr(dest);
int srcL = lenstr(src);
char * result = malloc(sizeof(char) * (destL + srcL));
int i;
for(i = 0; i < destL; i++){
result[i] = dest[i];
}
for(i = destL; i < destL+srcL; i++){
result[i] = src[i-destL];
}
return result;
}
Please make sure the caller frees up the result as shown below:
char * result = strcat1("hi", "ho");
printf(result);
free(result);
I wanted to make a simple str_join function in C (to learn a bit more about pointers and arrays), which literally joins two string together.
#include <stdio.h>
#include <stdlib.h>
int str_size(char *str);
void str_join(char *str1, char *str2);
int main(int argc, char **argv)
{
char *part1 = "Hello ";
char *part2 = "World!";
str_join(part1, part2);
printf("%s\n", part1);
return 0;
}
int str_size(char *str)
{
char c;
for(int i = 0;; i++)
{
c = str[i];
if(c == '\0')
return i + 1;
}
}
void str_join(char *str1, char *str2)
{
int str_size_1 = str_size(str1) - 1; //Last char is '\0', don't need them 2 times
int str_size_2 = str_size(str2);
char str3[str_size_1 + str_size_2];
int i;
for(i = 0; i < str_size_1; i++)
str3[i] = str1[i];
for(i = 0; i < str_size_2; i++)
str3[i + str_size_1] = str2[i];
str1 = (char *)str3;
}
It looks simple (maybe too simple).
I excepted the output to be:
Hello World
but it looks like:
Hello
I compiled the program using following command:
gcc main.c -o main
And ran it:
./main
I don't see my failure, could someone point me to my error?
Thank you for helping me out!
In C, function arguments are passed by value. Any changes made to any parameter from inside the function is will not reflect to the caller (actual argument).
So, in your case, str1 = (char *)str3;, does not do what you think it does.
That said, wait, stop!! str3 is a VLA and lifetime is the block scope. You cannot possibly return the address of the first element and expect that to be valid outside the scope for accessing the memory location(s). You need to allocate memory in such a way that it outlives its scope., You have to either
use an array with static storage (cannot be combined with VLAs)
use memory allocator function
You are not returning the pointer you think you are returning from the function.
str1 = (char *)str3;
You seem to assume that this changes str1 so that it points to the (correctly) joined string str3, but this change is not visible outside of the function.
You can fix this in (at least) two ways:
1) Allocate with malloc
char *str3 = malloc(str_size_1 + str_size_2);
And then return this pointer from the function (instead of void)
or 2)
pass a pointer to the pointer to the function, like this
void str_join(char **str1, char *str2)
And then
*str1 = str3;
The objective you wish to achieve is done with the help of call by reference method of the function calling method. But in your code, the str_join is a call by value function. When you change the value of str1 it is changed just for the scope of the function. As, soon as you come out of the str_join scope the value of str1 is again changed to the earlier one, becuase what you are passing to the function is not the address of str1 but a copy of the value of str1. You should try this instead :
void str_join(char **str1, char **str2)
// though the str2 need not to be passed by reference you can leave it as it is now
Replace the str1 inside the function with *str1
Then you can call it in your main function as : str_join(&str1, &str2)
The & sign signifies that you are passing the address of str1 and str2
I'm sure that there are many ways of implementing what is required here. A reasonably idiomatic way in C would be to create a new dynamically-allocated string large enough to hold both the original strings, and return that to the caller.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
char *str_join(char *str1, char *str2)
{
char *result = malloc (strlen (str1) + strlen (str2) + 1);
strcpy (result, str1);
strcat (result, str2);
return result;
}
int main(int argc, char **argv)
{
char *part1 = "Hello ";
char *part2 = "World!";
char *joined = str_join(part1, part2);
printf("%s\n", joined);
free (joined);
return 0;
}
The caller will have to call free() on the result. It's reasonable common practice to assume that any function that returns a "char *" is returning something that has to be freed, whilst a function that returns a "const char *" is returning something that doesn't need to be freed. A number of basic, long-standing functions in the C standard library don't follow this convention, however.
I need to convert arguments given at command line such as: $ myprogram hello world
and the words need to be printed in CAPS. I am able to to do everything except access the double pointer array to make the changes with toupper()
static char **duplicateArgs(int argc, char **argv)
{
char **copy = malloc(argc * sizeof (*argv));
if(copy == NULL){
perror("malloc returned NULL");
exit(1);
}
int i;
for(i = 0; i<argc; i++){
copy[i] = argv[i];
}
char **temp;
temp = ©[1];
*temp = toupper(copy[1]);
return copy;
}
*temp = toupper(copy[1]);
toupper converts a single character, if you want to convert an entire string:
char *temp = copy[1]; /* You don't need a double pointer */
size_t len = strlen(temp);
for (size_t i = 0; i < len; i++) {
temp[i] = toupper(temp[i]);
}
I assume the argument that is passed into your function char **argv is passed directly from main, so it represents a pointer to the beginning of an array of pointers to each of the command line arguments.
argc represents the number of command line arguments.
Inside your function, you create a new buffer, and then copy the contents of argv into it. So you are creating a copy of the array of pointers to the command line arguments, NOT the command line argument strings themselves.
I am guessing you intended to copy the strings, rather than the pointers to the strings (what would be the point of that?). I suggest you look into the functions strdup and/or strncpy to copy the actual strings.
This also explains with the 'toupper' does not work as you expect - instead of passing a single character to it, you are passing a pointer to a null terminated string of characters.
From the man page of toupper() the function prototype is
int toupper(int c);
In your code, the argument copy[1] is not an int value.
Instead what you want is to check each and every element, if they are in lower case, convert them to upper case. A pseudo-code will look like
for(i = 0; i<argc; i++){
copy[i] = malloc(strlen(argv[i])+ 1); //allocate memory
for (j = 1; j < argc; j++)
for (i = 0; i < strlen(argv[j]); i++)
{
if (islower(argv[j][i])) //check if it is lower case
copy[j-1][i] = toupper(argv[j][i]);
else
copy[j-1][i] = argv[j][i]; //do not convert
}
Consider this example:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
static char **duplicateArgs(int argc, char **argv)
{
char **copy = NULL;
// allocate memry for pointers to new lines
copy = (char **)malloc(sizeof(char *) * argc);
int line, chr;
for(line = 0; line < argc; line++)
{
// allocate memory for new line
copy[line] = (char *)malloc(sizeof(char) * (strlen(argv[line]) + 1));
// copy with changes
for(chr = 0; chr <= strlen(argv[line]); chr++)
{
copy[line][chr] = toupper(argv[line][chr]);
}
}
return copy;
}
int main(int argc, char * argv[])
{
char ** strs;
int i;
strs = duplicateArgs(argc, argv);
for(i = 0; i < argc; i++)
{
printf("%s\n", strs[i]);
}
return 0;
}
EDIT:
Also you can make a decision about using argv[0] (name of executable file) and change a code if you need. Also checking of malloc result can be added, and other improvements... if you need :-)
You are running into an error using the toupper() function because you are trying to pass in a string instead of an individual letter. Here is an excerpt from the man page describing the function:
DESCRIPTION
The toupper() function converts a lower-case letter to the corresponding
upper-case letter. The argument must be representable as an unsigned
char or the value of EOF.
You have a pointer to a pointer which you could visulize as something like this. In C a string is just an array of chars so you need to dereference twice to get the data in the second level of arrays (the individual letter). Every time you add an * you can think of it as removing one layer of pointers. And you can think of the * operator as the inverse of the & operator.
This line is your problem line
temp = ©[1];
try this instead
//This is a pointer to an individual string
char *temp = copy[1];
//Keep going while there are letters in the string
while(*temp != NULL) {
//convert the letter
toupper(*temp);
//Advance the pointer a letter
temp++;
}
I am trying to write a function that deletes a char c from a string src, and I am getting a seg fault when I try to run it. Here is the function.
void removeChar(char *src, char c){
int i, j = 0;
int size;
char ch1;
char str1[100];
size = strlen(src);
for (i = 0; i < size; i++){
if (src[i] != c){
ch1 = src[i];
str1[j] = ch1;
j++;
}
}
str1[j] = '\0';
src = str1;
}
And here is the main function where I am calling it.
int main(int argc, char **argv){
char *str = "Hello, world!\0";
printf("%s\n", removeChar(str, 'l'));
}
the return type of this function removeChar(str, 'l') is void not an char array and you are passing this to
printf("%s\n", removeChar(str, 'l'));
so here %s may give you the segmentation fault.
You assigned pointer src by the address of the first element of a local array
src = str1;
that will be destroyed after exiting the function. Moreover variable src is a local variable of the function so any changes of it do not influence the original pointer str.
Take into account that you may not change string literals. Any attempt to change a string literal results in undefined behaviour of the program.
Also the function has return type void and may not be used as an outputed object in function printf.
Type void is an incomplete type. It has no values.
And there is no need to append explicitly terminating zero to a string literal as you did.
"Hello, world!\0"
String literals already have terminating zeroes. So you could write simply
"Hello, world!"
As I already answered this question then you can visit my personal forum where there is a realization of the corresponding valid function.
If to declare correctly the function like
char * removeChar( char *s, char c );
then the main will look the following way
int main(int argc, char **argv)
{
char str[] = "Hello, world!";
printf( "%s\n", removeChar( str, 'l' ) );
}
You can print the string in the function itself! Then it works:
#include <stdio.h>
#include <string.h>
void removeChar(char src[], char c){
int i, j = 0;
int size;
char ch1;
char str1[100];
size = strlen(src);
for (i = 0; i < size; i++) {
if (src[i] != c) {
ch1 = src[i];
str1[j] = ch1;
j++;
}
}
str1[j] = '\0';
src = str1;
printf("%s\n", src);
}
int main(int argc, char **argv) {
char str[] = "Hello, world!";
removeChar(str, 'l');
return 0;
}
You have several bugs:
char *str = "Hello, world!\0";. Setting a non-constant pointer to point at a string literal is always wrong. Instead, declare the variable as const char *str. See this FAQ.
removeChar doesn't return anything so you can't pass it as a parameter to be printed by printf. Your compiler really should have complained here. Chances are that your compiler is misconfigured or you you aren't using it with all warnings enabled.
char str1[100]; You cannot use local variables and then try to pass the contents on to the caller. See this FAQ.
src = str1; doesn't do a thing, since src is only a local copy of the original pointer. With this assignment, you will not change the address of str in main. Which would have been a bug anyway, because of 3) above. You should rewrite your program so that is only uses src and no temporary array.
Not have enough reputation to comment. So, I had to write this on answer:
As Vlad from Moscow pointed out,
`a local array do not exist after the function terminate`
I suggest you obey the same principle as of standard library functions. If you didn't already notice,none string.h function allocate memory for the user. You must allocate before call.
char *str = "Hello, world!\0";
The above code do not guarantee a modifiable memory. The compiler can set them in read only memory. You should use a array instead.
I do not understand why the second printf loop outputs different data than the first printf loop that was done inside the function scope. Can it be that the pointer is changed somehow inside the function so that when it returns it returns a different value?
Output:
First printf inside function:
Parts TMP|01245
Parts X|40001
Parts Y|98760
Second printf outside function, in main:
It returns jiberish and not the same as when printing inside the function.
I tried to fprintf so that I can quickly paste the results in here ,but then I received an uninformative call stack error.
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
void ProtocolParse_Start(int *numParts,char **parts, char *str, const char* partsDelim )
{
int partCount = strChrCount(str,'~');
*numParts = partCount;
parts = (char**)calloc(partCount,sizeof(char));
char *tempPart;
tempPart = strtok (str,partsDelim);
parts[0] = (char*)calloc(strlen(tempPart),sizeof(char));
strcpy(parts[0],tempPart);
int i =1;
for(; i < partCount; i++)
{
tempPart = strtok (NULL, partsDelim);
parts[i] = (char*)calloc(strlen(tempPart),sizeof(char));
strcpy(parts[i],tempPart);
}
i =0;
for(; i < partCount; i++)
{
printf ("%Parts %s\n",parts[i]);
}
}
void ProtocolParse_End(int numParts,char **parts)
{
int i = 0;
for (; i < numParts; i++)
free (parts[i]);
free (parts);
}
int main()
{
char proto[32] = "TMP|01245~X|40001~Y|98760~";
char **parts;
int numParts;
ProtocolParse_Start(&numParts, parts,proto,"~");
int i =0;
for(; i < numParts; i++)
{
printf ("%Parts %s\n",parts[i]);
}
ProtocolParse_End(numParts,parts);
return 0;
}
Can anyone please shed some light onto my problem. Because I am not sure what I'm doing wrong ??
The assignment of parts inside the function has no effect on the char **parts from main. In order to modify it, you need to pass a pointer to parts, and add an extra level of indirection (yes, you'd get three asterisks now).
The code that partitions the data to strings is incorrect, too: you need to allocate an array of character pointers, and then copy each token into that array individually.
void ProtocolParse_Start(int *numParts, char ***parts, char *str, const char* partsDelim )
{
int partCount = strChrCount(str,'~');
*numParts = partCount;
*parts = malloc(partCount * sizeof(char*));
char *tempPart;
tempPart = strtok (str,partsDelim);
(*parts)[0] = malloc(strlen(tempPart)+1);
strcpy((*parts)[0], tempPart);
int i =1;
for(; i < partCount; i++)
{
tempPart = strtok (NULL, partsDelim);
(*parts)[i] = malloc(strlen(tempPart)+1);
strcpy((*parts)[i],tempPart);
}
i =0;
for(; i < partCount; i++) {
printf ("%Parts %s\n", (*parts)[i]);
}
}
I made three changes to your code:
Replaced calloc with malloc: you initialize every element anyway, so there is no reason to zero-fill the block
Removed casts in front of malloc - this is not necessary in C
Added one to strlen(tempPart) - you need this for null terminated strings.
There are different mistakes:
When you pass a parameter to a function it is always copied.
You gave a char **parts and it is copied.
Inside the function you overwrite the copied input with the new address of the calloced pointer.
Consider an easier example:
void doSomething(int a){
a=5;
}
///...
int b = 6;
doSomething(b);
When you call doSomething(b), your b is not changed.
If you want it to be changed, you have to pass a pointer to b.
void doSomething(int* a){
*a=5;
}
///...
int b = 6;
doSomething(&b);
The same is with your char*array.
You have char** partsin your main, that you want to be set to the allocated array.
so you have to pass its pointer. and write the obtained address to the dereferenced pointer.
The other big mistake is, that you gibe the wrong soze to the first calloc. It should be sizeof(char*).
Your routine should start like this:
void ProtocolParse_Start(int *numParts,char ***parts, char *str, const char* partsDelim )
{
int partCount = strChrCount(str,'~');
*numParts = partCount;
*parts = (char**)calloc(partCount,sizeof(char*));
char *tempPart;
//...
(all further accesses to parts in the function have to dereference parts)
and the call have to look like:
ProtocolParse_Start(&numParts, &parts,proto,"~");