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,"~");
Related
This is what I expect my string array s to be after the program is run: {"#0", "#1", "2"}.
This is what I am getting: {"#2", "#2", "2"}.
How do I modify this code so that I can get {"#0", "#1", "#2"} in the main after the function is executed?
What am I doing wrong? Please help.
#include <stdio.h>
void func(char **s){
for(int i=0; i<3; i++){
char buf[10];
snprintf(buf, 10, "#%d",i);
s[i]=buf;
}
}
int main()
{
char *s[3];
func(s);
for(int i=0; i<3; i++){
printf("%s", s[i]);
}
return 0;
}
First, you have every element in your array pointing to the same character array.
Second, they are all pointing to a local character array. This leads to undefined behavior.
Local variables in functions get allocated on the stack. When the function call is over, that memory may be overwritten with some other value.
Given two pointers p and q, the statement:
p = q;
doesn't copy the contents of the memory pointed to by q to the contents of the memory pointed to by p. It copies the pointer values, such that both p and q now point to the same memory, and any change to the memory via p is reflected when q is used.
That being said, the statement:
char buf[10];
declares buf to be an array of 10 chars. It has a lifetime corresponding to the execution of its block of definition. Once the function returns, it's destroyed and s is now indeterminate. Indeterminate pointers lead to undefined behaviour.
Possible Solutions:
standard strcpy
POSIX's strdup (which will be included in C23)
Note that the strdup() function returns a pointer to a new string which is
a duplicate of the provided string. Memory for the new string is obtained with malloc, and must be freed by the calling process with free.
#Chris’s answer tells you what is wrong.
To fix it, you have options. The simplest is to make the argument array have strings (char arrays) that are big enough for your uses:
#define MAX_STR_LEN (9+1) // Every string’s capacity is 9+1 characters
void func(size_t n, char array_of_string[][MAX_STR_LEN])
{
for (size_t i=0; i<n; i++)
{
snprintf(array_of_string[i], MAX_STR_LEN, "#%d", (int)i); // use the extant string
}
}
int main(void)
{
char array_of_string[3][MAX_STR_LEN] = {{0}}; // Array of 3 strings
func(3, array_of_string);
...
return 0;
}
If you want to play with dynamic char * strings, life gets only a little more complicated:
void func(size_t n, char *array_of_string[])
{
for (size_t i=0; i<n; i++)
{
free(array_of_string[i]); // free any pre-existing string
array_of_string[i] = calloc( 10, 1 ); // allocate our new string
if (!array_of_string[i]) fooey(); // always check for failure
snprintf(array_of_string[i], 10, "#%d", (int)i); // use the new string
}
}
int main(void)
{
char *array_of_string[3] = {NULL}; // Array of 3 dynamic strings, all initially NULL
func(3, array_of_string);
...
for (size_t i=0; i<3; i++) // Don’t forget to clean up after yourself
free(array_of_string[i]);
return 0;
}
Ultimately the trick is to manage the size of your strings, remembering that a string is itself just an array of char. You must ensure that there is enough room in your character array to store all the characters you wish. (Good job on using snprintf()!
Also remember that in C any argument of the form array[] is the same as *array. So our functions could have been written:
void func(size_t n, char (*array_of_string)[MAX_STR_LEN])
or
void func(size_t n, char **array_of_string)
respectively. The first is an uglier (harder to read) syntax. The second is nicer, methinks, but YRMV.
Finally, if you are using C99 (or later) you can tell the compiler that those arguments are, actually, arrays:
void func(size_t n, char array_of_string[n][MAX_STR_LEN])
or
void func(size_t n, char *array_of_string[n])
MSVC does not support that syntax, though, and probably never will, alas.
{ // start of a new scope
char buf[10]; // a variable with automatic storage duration
// ...
} // end of scope - all automatic variables end their life
In your code, you make pointers point at buf which has seized to exist (3 times) at the } in the for loop. Dereferencing (reading from the memory those pointers point at) those pointers afterwards makes your program have undefined behavior (anything could happen).
What you can do is to allocate and release memory dynamically using malloc and free.
When sending in a pointer to the first element in an array of elements to a function like you do, it's also customary to provide the length of the array (the number of elements in the array) to the function.
It could look like this:
#include <stdio.h>
#include <stdlib.h>
// A macro to calculate the number of elements in an array
// sizeof (x) - the number of bytes the whole array occupies
// sizeof *(x) - the size of the first element in the array
// (all elements have equal size)
// The result of the division is the number of elements in the array.
#define SIZE(x) (sizeof (x) / sizeof *(x))
void func(char *s[], size_t len) {
for (size_t i = 0; i < len; i++) {
// calculate the required length for this string
size_t req = snprintf(NULL, 0, "#%zu", i) + 1; // +1 for '\0'
// and allocate memory for it
s[i] = malloc(req);
if(s[i] == NULL) exit(1); // failed to allocate memory
snprintf(s[i], req, "#%zu", i);
} // dynamically allocated memory is _not_ released at the end of the scope
}
int main() {
char *s[3];
func(s, SIZE(s));
for (size_t i = 0; i < SIZE(s); i++) {
puts(s[i]);
free(s[i]); // free what you've malloc'ed when you are done with it
}
}
Note that with the use of the macro there is only one hardcoded 3 in the program. Even that could be made into a named constant (#define CHAR_PTRS (3) or enum { CHAR_PTRS = 3 };) to further the ease of reading and maintaining the code.
A non-idiomatic version only accepting a pointer to an array of a fixed (at compile time) size could look like like below. In this example you couldn't accidentally provide a pointer to an array with only 2 char* (which would cause the function to write out of bounds). Instead, it'd result in a compilation error.
#include <stdio.h>
#include <stdlib.h>
// Here `s` is a pointer to an array of 3 char*
void func(char *(*s)[3]) {
for (int i = 0; i < 3; i++) {
(*s)[i] = malloc(10);
if((*s)[i] == NULL) exit(1);
snprintf((*s)[i], 10, "#%d", i);
}
}
int main() {
char *s[3];
func(&s); // &s is a char*(*)[3]
for (int i = 0; i < 3; i++) {
printf("%s\n", s[i]);
free(s[i]);
}
}
#include <stdio.h>
#include <string.h>
void func(char **s){
for(int i=0; i<3; i++){
s[i]=malloc(sizeof(char) * 100);
char buf[10];
snprintf(buf, 10, "#%d",i);
strcpy(s[i], buf);
}
}
int main()
{
char *s[3];
func(s);
for(int i=0; i<3; i++){
printf("%s", s[i]);
}
return 0;
}
This fixed my problem. My understanding is that I assigned memory and then copied the contents of buf to s to the now-present memory.
The task would be to remove following characters that are repeating from a char array, like "deeeciddeee" -> "decide" or "phhhonne" -> "phone".
I have a function that crashes the console, and I can't spot the bug:
char* my_unique(char *first, char *last) {
char* ret=first;
for(int i=0; first+i!=last; i++){
if(first[i]==first[i+1]){
for(int j=i; first+j!=last; j++)
first[j]=first[j+1];
last--;
}
}
return ret;
}
it is called this way:
char* a="oooat";
a=my_unique(a, a+strlen(a));
cout<<a;
please help me!
Besides a small bug (you should add the line i--; after last--;, because you're deleting the character at possition i, so what has been the character at i+1 became the new character at possition i. If you don't decrease i, it will be increased and you jump over a character) the code runs perfectly fine IF it is called with
const char* b = "oooat";
char* a = new char[strlen(b) + 1];
for (size_t c = 0; c < strlen(a) + 1; c++) { a[c] = b[c]; }
a = my_unique(a, a + strlen(a));
cout << a;
delete[] a;
Notice that I've used a edit-able copy of the string, as the literal itself is of type const char* and therefor can't be changed at all. And as I said, this works perfectly fine and prints "oat", just as expected, without any crash. So your problem might be that you try to edit a const string literal? In that case you might consider to copy it, as I did, or use std::string (if you code in C++).
There are many beginner mistakes in the code.
Let me point you one by one.
char* a="oooat";
a=my_unique(a, a+strlen(a));
cout<<a;
When you declare a string like this : char* a="oooat", a is a string literal. The memory for the string is allocated into text section of the program. Which basically means you cannot modify the values inside the strings. You can only read from them. Hence when you are passing pointer a to the function and modifying it, it will result in segmentation fault(Illegal access to memory).
Why do you need a ret pointer here? char* ret=first;
You are passing a pointer and modifying the value inside it. Hence the new data will be reflected in the calling function and we need not return it explicitly. So, it is redundant.
Overall logic can be simplified as well
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MYSTR "ooooat"
void my_unique(char *first, char *last) {
int size = last - first;
int i = 0, j = 0, k = 0;
for (; i < size; i++, j++) {
first[j] = first[i];
// Continue to check how many repetitions are there
while (i + 1 < size && (first[i] == first[i+1])) i++;
}
// In the end terminate the string with a NULL.
first[j] = '\0';
return;
}
int main()
{
char a[] = MYSTR;
my_unique(a, a+strlen(a));
printf("%s", a);
return 0;
}
This is in C. There are simpler ways of doing this in C++, and the code can definitely be condensed but has been left simpler for readability.
#include <stdlib.h>
char* fix(char *input) {
char *lookahead = input;
char *newchar, *ret;
// Determine Max Return String Length
int len = 0;
while (*lookahead != '\0') {
len++;
lookahead++;
};
// allocate max possible memory needed and set the pointers
ret = malloc(len);
newchar = ret;
lookahead = input;
*newchar = *lookahead; // copy the first character
while (*lookahead != 0) {
lookahead++; // incrementing this ptr first starts lookahead at 2nd character and
// ensures the null terminator gets copied before the while loop ends
if (*newchar != *lookahead) { // only copy new characters to new return string
newchar++;
*newchar = *lookahead;
};
};
return ret;
};
I'll try to give my answer so that it makes the as little changes as possible to your original code, while using the simplest methods.
The main problem has already been identified by the previous comments - you cannot alter a string literal.
Also, the line of code
i--;
has to be placed as well, with the reason well clarified above.
While making an editable version of the string may be a good way of fixing the problem, a more straightforward way would be to make it a local string, as such :
char b[] = "oooat";
but doing this will make it incompatible with the return type of your my_unique function (char*). But why would you need a return type in the first place, if you are fixing the string itself?
My final code would look like this :
void my_unique(char *first, char *last) {
char* ret=first;
for(int i=0; first+i!=last; i++){
if(first[i]==first[i+1]){
for(int j=i; first+j!=last; j++)
first[j]=first[j+1];
last--;
i--;
}
}
}
making the function return void.
Hope this helps.
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 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.
I'm trying to pass the results array generated by sqlite3_get_table contained
in a function called by another function. Everything is working fine except I
can't get the array back into the main function. What exactly do I replace the
char **sql_results with? Here's the code:
int main()
{
char **sql_results = 0; // help here
sql_select_table("GetAirports", query_string, AIRPORTS_DATABASE,
sql_results, &RecordCount,
&ColumnCount);
for (int i = 0; i < ColumnCount; i++)
printf("%s\n", sql_results[i]); // Generates "EXC_BAD_ACCESS"
}
void sql_select_table(const char *query_name, const char *sql_query,
const char *sql_database,
char **sql_results, int *RecordCount,
int *ColumnCount)
{
sqlite3_get_table(open_database, sql_query,
&sql_results, RecordCount,
ColumnCount, &error_msg);
}
You're trying to take the address of one of the sql_select_table arguments and that doesn't do what you think it does; &sql_results is just the address of a local variable, it won't let you modify the sql_results in main().
Instead, pass a char*** into sql_select_table like this:
/* Note that sql_results is now a char*** */
void sql_select_table(const char *query_name, const char *sql_query,
const char *sql_database,
char ***sql_results, int *RecordCount,
int *ColumnCount)
{
sqlite3_get_table(open_database, sql_query,
sql_results, RecordCount,
ColumnCount, &error_msg);
}
int main()
{
char **sql_results = 0;
/* Note the & on sql_results */
sql_select_table("GetAirports", query_string, AIRPORTS_DATABASE,
&sql_results, &RecordCount,
&ColumnCount);
for (int i = 0; i < ColumnCount; i++)
printf("%s\n", sql_results[i]); // Generates "EXC_BAD_ACCESS"
}
Also, sqlite3_get_table is deprecated:
This is a legacy interface that is preserved for backwards compatibility. Use of this interface is not recommended.
So you might want to start using sqlite3_exec instead.